How do split shipments and partial fulfillments in historical order data migrate to Shopify's fulfillment-order model without breaking the audit trail?
Split shipments survive as fulfillment records, not as the original fulfillment orders. Shopify states plainly that fulfillment orders are created automatically when an order is created and that it is not possible to manually create fulfillment orders (per shopify.dev, September 2026). The audit trail you keep is tracking numbers and line-item quantities, not timestamps.
The model, and why it resists imports
Shopify's FulfillmentOrder "represents either an item or a group of items in an Order that are expected to be fulfilled from the same location" (per shopify.dev, September 2026). It is produced by Shopify's own routing: "After an order is created, a background worker performs the order routing process which determines which locations will be responsible for fulfilling the purchased items" (same source).
That routing is the point. Fulfillment orders are Shopify's answer to a question it asks itself, which is where should this ship from. A historical order already knows where it shipped from, so the routing has nothing to decide and every reason to decide it differently. Shopify closes the loop explicitly: "Shopify creates fulfillment orders automatically when an order is created. It is not possible to manually create fulfillment orders" (per shopify.dev, September 2026).
What you can and cannot preserve
| Historical fact | Preserved? | How |
|---|---|---|
| Which line items shipped together | Yes | Fulfillments created against the auto-generated fulfillment orders, one per historical shipment |
| Quantities per shipment | Yes | lineItemsByFulfillmentOrder takes explicit quantities (per shopify.dev, Sep 2026) |
| Carrier and tracking number | Yes | trackingInfo accepts company, number and URL (same source) |
| The date each shipment left | No | fulfillmentCreate exposes no historical date field |
| Which physical location shipped it | Only if that location exists in Shopify with the same identity | Routing assigns the location; a legacy warehouse that was not migrated cannot be named |
| The original fulfillment-order grouping and its state changes | No | Created by Shopify's router, not by you |
The practical consequence: your audit trail changes shape
Before migration, the audit trail is chronological. It says this carton left this warehouse on this date. After migration, the audit trail is compositional. It says these three units were fulfilled under this tracking number against this order. For most audit purposes the second is enough, because the question asked is usually "did the customer receive what they paid for" rather than "on which Tuesday".
Where the chronological version is genuinely required, say for a carrier claim or a service-level dispute, the answer is the same as it is for returns: keep the old record, in the old format, for as long as the obligation runs. Do not try to reconstruct a timeline inside a system that does not store one.
A sequencing rule that avoids the worst version
Migrate locations first, then products, then customers, then orders. If locations arrive after orders, Shopify routes every historical shipment to whatever location existed at import time, and every fulfillment then attaches to the wrong place. Re-pointing them afterwards means deleting and re-importing the affected orders, because the fulfillment order they hang from is not editable into a different assignment for historical purposes.
When NOT to reproduce split shipments at all
- When the order is fully delivered and closed. A single fulfillment carrying all line items and the last tracking number is often the honest simplification, and it should be recorded as a deliberate simplification in the migration mapping document rather than discovered later.
- When the legacy warehouse no longer exists. Inventing a Shopify location to host dead history pollutes every inventory report thereafter.
- When the 3PL is also changing. Historical shipments attributed to a 3PL location that now belongs to a different provider will confuse the provider's own reconciliation.
- When order volume is very large and the value is presentational. Multi-shipment reconstruction multiplies API calls per order; price it before committing.
The Deploi point of view
Our own position, from building on Shopify. Separate from the facts above.
- Our take: Decide per cohort, not per order. We split historical orders into closed and open at the cutover date, reproduce split-shipment detail only for the open cohort where operations still needs it, and simplify the closed cohort to one fulfillment plus a link to the archive. That decision belongs to the ops lead, in writing, before the import is built.
- Where we disagree: Migration scopes treat fulfillment fidelity as a quality measure and try to reproduce every shipment. The constraint that makes this a losing trade is documented and rarely quoted: you cannot create a fulfillment order, and you cannot date a fulfillment. So maximum effort buys you a partial reconstruction with today's timestamps, which reads as precise and is not. A smaller import plus a retained archive is more truthful and costs less.
- What this page adds: that fulfillment orders are generated by Shopify's routing worker and cannot be created or backdated, and that locations therefore have to be migrated before orders or every historical shipment attaches to the wrong place.
Reviewed by Martin Dejnicki, Director of SEO & AI Search. Facts verified 2026-09-14.
Where we worked this out
Our decision records