Why inventory sync is harder than it looks

The basic version of NetSuite → Shopify inventory sync is straightforward: read inventoryItem.quantityAvailable from NetSuite on a schedule, write it to Shopify's inventory_levels endpoint per location. Celigo's native connector covers that case with minimal custom logic.

The hard version — which is what most mid-sized businesses actually have — involves multiple NetSuite subsidiary locations, Shopify markets with different fulfilment sources, bundle SKUs that don't exist as discrete items in NetSuite, and the question of what "available" actually means when you have open sales orders, drop-ship POs, and a 3PL in the mix.

This article covers the decisions you need to make before you configure the flow, not after.

Decide what "available" means first

NetSuite exposes several quantity fields per item per location:

Most teams default to quantityAvailable and that is usually right. But if you fulfil from one warehouse while purchasing into another, you may want to aggregate across locations before writing to Shopify — in which case you need a SavedSearch that sums across location IDs, not a direct item lookup.

Common mistake

Using quantityOnHand instead of quantityAvailable means Shopify will show stock that is already committed to other orders. This usually surfaces as oversells within two to three days of going live.

Batch vs real-time: the honest trade-off

Celigo supports both scheduled and real-time (webhook-triggered) flows. For inventory sync the decision is not about preference — it is about volume and error tolerance.

Real-time works when your NetSuite item count is low (under roughly 2,000 active SKUs), your Shopify store is a single location, and you can accept the additional API call load. You set up a NetSuite saved search with a lastModifiedDate filter, poll every two to five minutes, and push delta changes to Shopify.

Batch works when you have high SKU counts, multiple locations, or when your team cares more about data consistency than latency. A nightly or twice-daily full sync is easier to debug and easier to test.

NetSuite saved search filter — delta sync SuiteScript expression
criteria.addFilter({
  name: 'lastmodifieddate',
  operator: 'onOrAfter',
  values: ['{lastRunDate}']
});

Multi-location mapping

If Shopify has multiple locations you need to map each NetSuite location ID to a Shopify location ID. Celigo handles this in the import's field mapping step using a static lookup table or a handlebar expression that reads from a reference dataset.

The main failure mode here is when a new NetSuite location is added and no one updates the mapping. The flow continues running silently and the new location's inventory never reaches Shopify. Build a lookup not found alert on the mapping step to catch this before it causes a problem.

Bundle SKUs and assembly items

If you sell bundles in Shopify that correspond to Assembly Items or Kit Items in NetSuite, the inventory calculation is not a direct field read. Options:


What to build first

Our recommended sequence: start with a batch full sync on a six-hour schedule for all simple items (no bundles, single location). Validate the data matches in both systems. Then layer in delta sync for high-velocity SKUs. Then tackle bundles as a separate flow that reads component quantities from a saved search.

If you try to solve everything in one flow on day one, you will spend three weeks debugging edge cases that affect 3% of your catalogue while 97% of your inventory is just fine.

Work with us

We have built this flow for several Shopify + NetSuite clients. If you want to walk through your specific catalogue structure before configuring anything, get in touch at [email protected] — it is usually a 20-minute conversation.