Shipping
Learn how shipping rates are scoped without a zone model, which carriers get tracking links, and where arrival estimates come from.
Shipping rates are scoped by country, location and channel. There is no zone model, field or route anywhere in the codebase.
A zone is normally an extra layer of indirection: rates belong to zones, zones contain countries, and every question about a rate becomes two lookups. Here a rate names the countries it serves directly.
The cost of that is that two rates covering the same twenty countries repeat the list. The benefit is that reading a rate tells you where it applies, without resolving anything.
How a rate is scoped
A rate carries a list of country codes — an empty list meaning everywhere — plus an optional location and an optional channel.
The three are independent filters, and each has a meaningful empty state:
- an empty country list serves every country
- a null location means the rate is not tied to a particular warehouse
- a null channel means the rate is global and available to all channels
A rate also carries a minOrderAmount and a maxOrderAmount, either of which may be unset.
Free shipping is not a separate concept. It is a zero-priced rate with a minimum order amount.
That is the whole feature. There is no free-shipping flag to keep in sync with a threshold, and no second code path that suppresses a charge — the charge is simply zero on a rate the cart qualifies for.
Fulfilment methods
A rate's type is one of:
delivery
pickup
digitalIt is a string label, not a database enum, so a new method — a locker, a courier — can be added without a migration. The canonical values live in lib/db-enums.ts and the matching zod enum.
Rates are ordered by an explicit position, so the order the shopper sees at checkout is the order the operator arranged, not an accident of insertion.
Currency
Each rate carries its own currency, and only rates in the checkout session's currency are surfaced.
That is not a display nicety. Stripe rejects a session whose shipping_options do not all match the session currency, so a single mismatched-currency rate would break checkout entirely for a multi-currency store.
The price is also carried as an amount and its currency together, inseparably, so no consumer can read the number without the currency it is denominated in.
A rate's currency is part of its scope
A rate priced in a currency the session is not using is not a cheaper option or an approximate one — it is invisible. If a market shows no delivery options, check the rate currencies before checking the country lists.
Tracking
Tracking URLs are built automatically for four carriers:
usps
ups
fedex
dhlThat set is the carrier dropdown in the editor. Because it is small and known, the customer-facing "Track your package" link can be derived from the carrier and the tracking number, instead of the operator hand-pasting a full URL for every shipment.
Anything else records the tracking number with no link.
buildTrackingUrl returns null for an unknown or internal carrier, and null for a missing number. The caller then falls back to an explicitly entered URL, or leaves the link blank — a shipment with an unrecognised carrier still records its number and still shows it.
Estimates
Arrival estimates come from a working-days and holiday-closures setting rather than from a carrier API. Nothing calls out to a carrier to ask when a parcel will land.
An estimate is derived on read and never stored:
handling (processing) time
+
the rate's transit days
↓
counted in the store's working daysThe rate supplies minDays and maxDays. Either may be null when the rate does not quote that bound, and the corresponding end of the window is then null too — an unquoted bound is reported as unknown rather than guessed.
The working days are not assumed. The store's configured fulfilment calendar decides which days count: which weekdays it ships, plus its own holiday closures. The default is a Monday-to-Friday week, but that is a default rather than a baked-in rule, so a Friday/Saturday weekend, a seven-day dropshipper, and a maker who only dispatches on Mondays, Wednesdays and Fridays all get an estimate that matches how they actually operate.
Because the math lives in one place, the product page, the cart and the order page cannot disagree about when something arrives.
Where a new shipping rule goes
If the rule is about where a rate applies, it is a scope field on the rate — countries, location, channel — not a new branch at checkout.
If it is about when a parcel lands, it belongs in the estimate function or the fulfilment calendar, so every surface that quotes a date quotes the same one.
If it is about a carrier's own systems, be careful about what is actually being promised. A tracking link is derived from a number the operator typed; it is not a status the application knows.
The question to ask is:
Is this a fact the store configured, or a fact only the carrier knows — and which of those am I about to show the customer?
Related
Tax
Learn how the tax provider seam resolves a rate, why Stripe Tax falls back to the flat channel rate, and what is deliberately left unwired.
Checkout
Learn how a cart becomes a Stripe Checkout Session, how long stock is reserved, and why the reservation window must outlive the payment window.
Inventory
Learn how stock is summed from locations on read, how a stock movement is constrained by the database, and how concurrent checkouts are serialised.