Shopify bundle variant trees: size and color matrices inside packs without SKU explosion
How to design size×color (and similar) variant trees inside Shopify product packs so shoppers pick the right component variants — without exploding unstockable combinations or breaking component-level inventory sync.
Jeshua Leger
Founder, Leger Studio ·
Apparel, beauty, and gear catalogs do not sell “the hoodie.” They sell Medium / Black, Large / Heather, and every size×color cell that actually exists in the warehouse. When you turn those products into packs — starter kits, complete-the-look sets, gift boxes with a sizeable hero — the same option space shows up inside the pack. Merchants who ignore it ship one fixed SKU and eat returns. Merchants who mirror the full matrix on the pack product often invent combinations nobody stocks.
A **variant tree** is the deliberate map of which options live on the pack, which options stay on components, and which cells you refuse to sell. This guide is that map. It sits next to fixed-price product packs (exact shelf price) and kit inventory sync (availability from components). Those posts assume a known component list. This one answers: *how do size, color, shade, and scent options branch inside a checkout-native pack without blowing up SKUs or lying about stock?*
What a pack variant tree actually is
Think of three layers, not one “variants” toggle:
- Pack product — the single PDP customers add to cart. It may expose options (Size, Color) when the shopper must choose something that changes which component variant ships.
- Component products — the real SKUs fulfillment picks. Each already has its own variant grid in Shopify.
- Binding rules — which pack option values select which component variants, and which combinations are unpublished because you cannot stock them.
The tree is the binding layer. Without it, you either freeze the pack to one component variant (easy, narrow) or publish a Cartesian product of every option on every component (easy to generate, impossible to operate). The useful middle ground is a **constrained tree**: expose only the options the shopper must decide, pin the rest to merchandising defaults, and cut dead branches before they reach the storefront.
When a fixed single-SKU pack is enough
Not every kit needs a matrix. Prefer a single pack variant when:
- All components are one-size / one-SKU goods (candles, supplements, accessories with no fit).
- The “choice” is already made by which pack product you published (Summer Kit vs Winter Kit as separate products).
- You are still proving pricing and checkout math — see the fixed-price pack checklist — and option complexity would hide whether Functions allocation is clean.
- Returns data shows size/color complaints are rare for that category.
Add a tree when the shopper’s decision changes a **fulfillment SKU**, not just marketing copy. Size on a hoodie in a “hoodie + beanie” set qualifies. “Gift message” that does not change inventory usually belongs in line-item properties or a note field — not a variant explosion.
The explosion problem (and how to count it)
Cartesian product math is how catalogs die. Example:
- Hoodie: 5 sizes × 4 colors = 20 variants.
- Beanie: 3 colors.
- Naive pack that exposes hoodie size, hoodie color, *and* beanie color independently = 5 × 4 × 3 = **60 pack variants** — many of which you never purchased as a set.
Each pack variant still needs honest availability from its bound component variants. Sixty cells means sixty inventory stories. Ops will not keep them accurate by hand. Merchandising will not QA discount allocation on sixty combinations before BFCM.
A practical ceiling
Treat **12–24 live pack variants per pack product** as a soft ceiling for the first release. Above that, split into multiple pack products (e.g. “Navy set” and “Black set”) or drop an option from the pack and fix it merchandising-side. The ceiling is operational, not a platform hard limit — it is how many cells you can stock, price-check, and support.
Decide which options live on the pack vs the component
Use this ownership test for each option name:
- Does the shopper *must* choose it for the pack to be wearable / usable? → Candidate for a pack option.
- Does every reasonable pack share the same value (e.g. always include the black beanie)? → Pin it; do not expose it.
- Does the option only exist on one component and never change which *other* components ship? → Prefer selecting that component’s variant in the tree rather than adding a second pack-level axis that multiplies everything.
- Would two pack options select the *same* underlying SKU under different labels? → Collapse them. Duplicate labels create false stockouts.
Common good patterns:
- Apparel set — pack options: Size (+ maybe Color). Companion accessories pinned to one SKU or a short curated color map.
- Beauty routine — pack options: Shade on the hero only. Toner and moisturizer stay single-SKU or use a separate “skin type” pack product.
- Gear kit — pack options: Size on the primary hard good. Consumables and tools stay fixed.
Binding rules that keep fulfillment honest
Every published pack variant must resolve to an exact list of component variant IDs and quantities. Ambiguity (“any Medium hoodie”) is how warehouses guess wrong.
- One pack variant → one binding. No “or” logic at pick time.
- Shared components across packs still decrement the same variant inventory — trees do not invent a second stock pool (kit inventory sync).
- If Size M / Color Black on the pack maps to hoodie variant H-M-BLK and beanie B-BLK, write that row in your merchandising brief and keep it identical in the app.
- When a component variant is discontinued, unpublish or remap the pack variants that pointed at it *before* you zero the component — otherwise the pack PDP can outlive the SKU.
Checkout must still expand the pack into those real component lines with allocated discounts. That is the same Functions contract as non-variant packs — see discount allocation and discount modes docs. Variant trees change *which* SKUs appear; they should not change the rule that line discounts sum cleanly to pack savings.
Inventory: the shortest branch wins
Pack availability for a given pack variant is still limited by the scarcest bound component variant (adjusted for quantity per pack and any reserve buffer). The tree multiplies how many of those calculations you run.
- Sellable qty for Pack / M / Navy = min over components of floor(component_variant_on_hand / qty_needed).
- A popular size can sell out the pack even when other sizes still look fine on the PDP — that is correct behavior.
- Colorways you never bought for the companion item should not appear as pack options that imply they do.
- Multi-location brands: cover is per shipping location. A pack variant “available” company-wide can still fail at the node that picks DTC — pair this guide with multi-location transfers when imbalance, not option design, is the bottleneck.
Merchandising patterns that stay within the ceiling
1. Size-only tree on a fixed color story
Publish “Essentials set — Black” as one pack product with Size S–XL. Color is decided by the product, not an option. Four to five pack variants. Companion items stay black-only. Clean feeds, clean creative, honest stock.
2. Split color into separate pack products
Instead of Size × Color on one PDP, ship “Navy set” and “Sand set,” each with Size only. You keep two PDPs and ~5 variants each instead of one PDP with 20+. Ads and email can deep-link the color the creative already showed.
3. Hero-option tree, companions pinned
Expose Shade (or Fit) only on the hero component. Pin the free gift or accessory to one SKU. This is the usual gift-with-purchase shape when the gift does not need a shopper choice.
4. Curated allowed pairs (not full Cartesian)
If two components both have color, publish only the pairs you photograph and stock: Navy hoodie + navy beanie, Black hoodie + black beanie — not Navy hoodie + red beanie unless that look is intentional and purchased. Allowed-pair lists are trees with pruned branches.
Pricing and allocation across the tree
Keep pack *price mode* stable across variants unless you have a documented exception. Shoppers (and ads) expect “Routine kit $79” to mean every size at $79 — not Medium at $79 and XL at $91 because someone forgot a row.
- Prefer one fixed pack price (or one percent/amount-off rule) for the whole tree when component list prices are similar across sizes.
- If a size truly costs more (extended sizes, premium colorways), either split into a second pack product with a clear title or accept a different pack price *and* update every creative that quotes the old number.
- Allocation mode (spread vs free-item) should be identical across the tree so support macros stay one paragraph (discount modes).
- QA at least two pack variants on paid test orders — a cheap size *and* a scarce size — so you catch binding mistakes that a single happy-path order misses.
QA checklist before you advertise the matrix
- Count published pack variants; cut anything you cannot stock for the campaign window.
- For each published cell, write the bound component variant SKUs and quantities; spot-check three cells in admin.
- Confirm pack sellable qty matches the shortest component for a known low-stock cell.
- Place test checkouts on two pack variants; verify Functions line discounts and fulfillment SKUs (Functions allocation guide).
- Refund/exchange playbook: which component variant returns when the customer picked Size L.
- Feed and pixel check: only published variants sync; titles include size/color the creative promises.
- Support macro: one sentence explaining how to choose Size/Color on the pack PDP.
If AI suggested the *contents* of the kit from co-purchase data, still build the tree by hand. Co-purchase → pre-draft → push is about *what* to bundle; variant trees are about *which option cells* you will defend in inventory and ads.
Plan notes: when Growth-level variant support matters
On Better Bundles, Basic ($0 forever, up to 3 active bundles, limited AI) and Starter ($17/mo, unlimited bundles, inventory sync, up to 30 AI recommendations) cover straightforward packs. **Variant matrices for packs sit with advanced bundle types on Growth ($37/mo, up to 100 AI recommendations) and Pro ($77/mo, unlimited AI and bundle revenue).** Paid plans include a 15-day trial billed through Shopify.
If you are still validating one fixed kit, stay on the simpler path — create the offer, publish, QA checkout (first offer walkthrough). Graduate to a tree when returns or “wrong size in kit” tickets prove the shopper needs a choice on the pack itself.
Ship one constrained tree this week
Pick a hero pack that already has margin at a clear price. Expose **one** shopper option (usually Size). Pin companions. Publish at most a handful of cells you can stock. Run two test orders. Only then point ads at the pack PDP.
Install from apps.shopify.com/better-bundles, read Getting started and Inventory sync & stock management, and keep the tree in your merchandising brief next to pricing and allocation. For kit-shaped offers without options, the product kits use case stays the shorter playbook. If the hard problem is stock sitting in the wrong building rather than option design, follow FlowOps (in development; pricing TBD) while you keep transferring with native Shopify tools.