Shopify shipping rates for packs that expand at checkout
Why a Shopify Functions pack is rated on its component lines, not the pack product’s weight — how weight-based, price-based, and carrier-calculated rates read an expanded pack, the $0 gift that adds a second shipping rate, split shipments from mismatched locations, decision rules by whether components also sell solo, and a 15-minute rate test before launch.
Jeshua Leger
Founder, Leger Studio ·
The Morning Routine Kit ships in one mailer. You weighed it: 620 g, box included. So you opened the kit’s product in the admin, typed 620 g into the weight field, and published. The first order is rated at 1,150 g — cleanser 300 g, serum 250 g, travel bag 400 g, plus your 200 g default package — and the customer paid the next weight band up. The field you edited had no vote. A pack sold as one product and expanded by Shopify Functions at checkout is rated on the component lines that come out of the expansion, and every shipping setting that matters lives on those components.
This post does one job: get a pack’s shipping rate right before launch — which weights, shipping profiles, and locations checkout actually reads once the pack expands, the three ways a correct pack produces a wrong-looking rate, and decision rules for component weights when the same SKUs also sell on their own. It is not the post about what the warehouse prints (pack lines your 3PL can pick) or about whether a free-shipping discount survives next to a pack (discount stacking with packs). Those are about documents and discounts. This one is about the rate the customer sees on the shipping step.
What checkout rates after the pack expands
Shopify calculates shipping from the cart lines that exist when the shipping step runs. For a Functions pack that is the expanded set: component variants with their own weight, their own shipping profile, their own “this is a physical product” flag, and their own stock at each location. Shopify says so plainly for its own Cart-Transform-based Bundles app — weight is derived from the individual item weights, not the bundle product’s weight, and bundles do not have shipping profiles of their own — and the same platform mechanics apply to any pack that expands the same way. Third-party carrier apps see it from the other side: a rate request lists the expanded component items and carries no reference to the parent pack at all. Four consequences to internalize before touching a rate table:
- The pack product’s own weight field is not read at checkout. Fill it in for your own records if you like, but nothing downstream is rated on it.
- The pack product cannot be put in a shipping profile in any way that matters. Its components can — and each one carries its own profile into the cart.
- The box you actually ship is not what gets rated unless the component weights add up to it. Cart weight is arithmetic on component records; ship weight is what the scale says. Your job is to make them agree.
- Quantity scales linearly. Two kits are two of each component line, so the rated weight doubles exactly — correct for multipacks, and a reason a 6-pack of something light can still cross a weight band you did not expect.
Rate type by rate type
Weight-based rates
The rated weight is the combined weight of the component lines shipping from the same location under the same option, plus your store default package weight. In the opening example: 300 + 250 + 400 + 200 = 1,150 g against a kit that physically ships at 620 g. Three ways this goes wrong on a pack that is configured correctly:
- A component with no weight recorded contributes 0 g, so a pack of three unweighted items rates like an empty box. Shopify warns that weight-based rates do not calculate correctly with missing weights; a pack multiplies the blind spot by its component count.
- Component weights were entered as “weight of that item packed and shipped alone” — item plus its own mailer. Solo orders rate fine; a pack sums three mailers plus the default package and lands a band or two high.
- A gift component that physically weighs almost nothing (a card, a sample sachet) was given a placeholder weight so the field was not empty. In a pack it is real grams on every order.
Price-based rates
Shopify determines price-based rates from the cart’s value after discounts and before tax. A $79 pack should therefore land in the $79 band whichever application mode you run: on product-level application the component lines already sum to $79; on order-level application (Growth and Pro) the lines read $100 with a −$21 order discount, and the rated value is still $79. A $0.00 gift line in free-item mode contributes nothing, as it should. Do not confuse this with a free-shipping discount that has a minimum purchase requirement — that is a discount, combined under discount rules, and can behave differently by mode. The stacking post covers that side; the rate table is the simpler of the two.
Carrier-calculated and app-calculated rates
Live carrier rates are quoted from the shipment weight plus your default package dimensions, so the same component-weight arithmetic applies, and dimensional weight is computed from the default package — not from anything on the pack or its components. If a kit ships in a box much smaller than your store default, the customer is quoted on the bigger box. Third-party rate apps receive the expanded components with their grams, prices, and physical-product flags, and no parent reference, so a rule like “kits ship flat $6” cannot be keyed on the pack. If a component set is unique to one pack, an app can infer it; if the same items also sell à la carte, it cannot tell a pack from a hand-built cart of the same three items — and neither can you, from the rate request alone.
The $0.00 gift that adds a second rate
This is the pack-specific failure and the one that produces tickets. Shipping profiles belong to products. When a cart holds products from two profiles, Shopify calculates a rate for each profile and adds them together — its own example is two $5 discounted-shipping rates becoming $10 at checkout. For weight-based rates the split goes further: when rates are combined across profiles or locations, the default package weight is added to each product’s weight separately, and each product is rated on its own before the rates are summed.
Now put a gift-with-purchase pack through it. The hoodie lives in the General profile. The stand was set up months ago in an “Accessories — oversized” profile with its own rate table. The pack is one product on the storefront and one line in the cart, so nobody thinks about profiles — until checkout expands it, finds two profiles, and shows the customer the hoodie’s rate plus the stand’s rate. The gift is free on the line and costs $7.95 to ship. The ticket reads “shipping doubled when I added the bundle,” support checks the pack settings, finds nothing, and escalates a bug that is a shipping profile.
Locations: the pack counts stock, the components ship
Better Bundles computes how many packs are sellable from component stock at the locations you configure — store-wide in Settings → Inventory, or a custom set per bundle. That decides whether the pack shows as available. It does not decide where anything ships from. After the order lands, Shopify’s routing rules assign each component line to a fulfillment location on its own, exactly as for any order with three products on it. If the cleanser and serum are at the hub and the travel bag is only in stock at a retail store, the order splits: two fulfillments, two labels, and — because rates combine across locations the same way they combine across profiles — a customer who paid one rate per location at checkout, or a merchant who ate the second label if the rate table did not.
- Restrict the pack’s counted locations to the ones that hold complete sets. A pack that only counts hub stock cannot sell when the hub is missing a component, which removes the most common split by construction. It does not override routing — it removes the orders that would have needed it.
- If a component keeps drifting to one location, that is a stock-position problem, not a pack problem: move it. Order routing vs inventory transfers is the decision guide for which lever to pull.
- The reserve buffer is not a routing tool. It holds back pack units so components stay available for solo sales; it does not change which location a component ships from.
Decision rules for component weights
Because the weight lives on the component and the component may sell in more than one way, the right number depends on how that SKU sells. Four cases cover almost every catalog:
- Sold solo and in packs (the usual hero). Record the item’s own weight — no mailer — and let the default package carry the packaging. The pack then rates as the sum of item weights plus one package, which is usually within a band of the real box. Never lower a hero’s weight to make a pack cheaper to ship; every solo order of that hero under-rates from then on.
- Sold only inside packs (a branded pouch, a stand that exists for the gift offer, a sample size). Set its weight to the grams it actually adds to the packed kit — which may be close to zero if it rides in space the hero’s box already had. This is the one lever that lets cart weight converge on ship weight without distorting anything else.
- Same-SKU multipacks. Sum is correct by definition; the risk is the band. A 6-pack of 180 g items plus a 200 g package is 1,280 g. Check the multipack against your table before publishing, not after the first order. The same-SKU multipacks playbook covers the merchandising side.
- Not a physical item at all (an extended warranty, a digital guide bundled with a device). Turn off “this is a physical product” on that component so it carries no weight and no profile into the rate. If it is left on with a zero weight, it is harmless for weight but still a product in a profile — and can still split a rate.
Two things you cannot do, so plan around them. You cannot give the pack alone a special shipping rate through the rate table, because the table never sees a pack; if the pack price clears a free band on price-based rates, it gets it, and otherwise free shipping for a pack is a shipping discount with all the combination rules that come with one. And you cannot set a pack-level dimension for dimensional weight; if a kit ships in a box far smaller than your default package and carriers are quoting on the default, the honest fix is a smaller default package or a marked-down carrier rate, not an edit to the pack product.
Read the label, not just the rate
The rate is what the customer paid; the label is what you paid. When you buy a label, the pre-filled weight is built from the line items in the fulfillment, so it inherits the same component arithmetic — and the carrier bills on the scanned actual or dimensional weight regardless of what the label said. For the first twenty pack orders, keep three numbers per order: rated weight at checkout, label weight as pre-filled, and the weight your packer read off the scale. A consistent gap in one direction is a component-weight problem with an obvious fix from the rules above. A gap that appears only on some orders is a profile or location split — look at the fulfillments tab, not the weights.
A 15-minute rate test before the pack goes Active
Run this once per pack, and again when a component’s weight, profile, or stocked locations change — the pack will not tell you, because the pack did not change.
- Pack the kit as it will ship and weigh it. Write that number down first; it is the target.
- For each component, read the weight, the shipping profile, the physical-product flag, and the locations with stock off the admin. Add the weights and your default package weight. If this sum and step 1 disagree by more than a band, decide which component weight to fix using the rules above before testing anything.
- Open the storefront, add the pack alone, and go to the shipping step for one address per zone you ship to. Note the rate and, if you offer several options, all of them.
- Clear the cart and add the components individually at the pack’s quantities. The rates should be identical to step 3, because checkout is rating the same lines. If they differ, a component changed between save and expansion — re-save the pack and check Settings → Checkout functions per the troubleshooting doc.
- Add a second pack. The rate should move exactly as two of each component would. Then add one solo hero to a single pack and confirm the band it lands in is the one you expect from the sum.
- If you use price-based rates, build one cart just under and one just over each band using the pack price. If you run order-level application, repeat once — the rated value is after discounts in both modes, and the test proves it on your store rather than on this page.
- Place a real test order to a zone where more than one location could fulfill it and look at the fulfillments tab. One fulfillment is the goal. Two means a location split, and you go back to the pack’s counted locations before you touch a rate.
- Start a label on the test order, compare the pre-filled weight to step 1, then void it. Write the three numbers on the pack’s launch card next to the allocation and application modes, so the next person who reads a shipping ticket knows what a correct one looks like.
A pack is easy to ship when the components tell checkout the truth, because the components are the only thing checkout is listening to. Better Bundles expands each pack into its real component lines at checkout on every plan, computes pack availability from component stock at the locations you choose, and leaves shipping profiles, weights, and routing exactly where Shopify keeps them — on the products your warehouse already ships. Basic is free forever with up to 3 active bundles; Starter, Growth, and Pro are $17 / $37 / $77 a month with a 15-day trial. Build the pack in create your first bundle, run the rate test before it goes Active, or install from the Shopify App Store and start with the kit you already weigh by hand.