Kits vs bundles
Kits and bundles both group other products together through the same underlying product_components relationship, and you build both in the same Workshop. But they behave in opposite ways once a product exists in the system: a kit is a real stock item that can hold or be assembled into inventory, while a bundle is a virtual marketing wrapper that never holds stock of its own and is expanded into its parts the moment it lands on a sales order.
Getting this distinction right matters because it decides where a product's stock lives, how it's fulfilled, how it's costed, and how its demand shows up in forecasting. This page explains the model; for the field-level definitions of components, see the Kit & bundle component reference, and to see how each product type behaves overall, see Product types explained.
The fundamental difference
The single flag that changes everything is the product's type. In the catalog, bundle and kit are two of the six product types, and only some types hold inventory.
| Aspect | Bundle | Kit |
|---|---|---|
| Holds its own stock | No — it's not an inventory-bearing type | Yes — a kit is an inventory-bearing type |
| What it's | A sales/marketing concept: "buy these together" | A physical assembly you can stock or build |
| At order entry | Expanded into separate component sales-order lines | Stays a single line; fulfilled from kit stock or assembled |
| Fulfillment | Each component is picked and shipped individually | Ship a pre-built kit, or assemble one from components |
| Costing | Revenue is prorated across components | The kit carries its own cost and FIFO layers |
| Can be a component of another product | No | Yes — a kit can nest inside another kit or a bundle |
A bundle exists only to sell things together. Because it's not one of the inventory-bearing product types, it never has an on-hand number, a FIFO layer, or an opening balance. When a bundle is added to a sales order, SKU.io transforms that bundle line into one line per component before the order is fulfilled — the bundle disappears and its parts are what actually get picked, shipped, and decremented from stock. Bundle revenue is then prorated across those components so each line carries its fair share of the sale.
A kit is a real product that holds stock. It can be fulfilled two ways: from pre-built kit stock already sitting on a shelf, or by assembling one on demand from its component stock. Both paths are valid at the same time — a warehouse might have three kits already built and enough loose components to build twelve more. Because a kit is inventory-bearing, it has its own on-hand quantity, its own cost, and its own FIFO layers, just like a standard product.
What can be a component
Only standard and kit products may be added as components. A bundle can't be a component of anything — allowing it would mean nesting a thing that has no stock inside another grouping, which the expansion and assembly logic can't resolve. A kit, by contrast, is allowed as a component precisely because it does carry stock and can itself be flattened.
Converting a product's type is guarded: you can only switch between bundle and kit while the product has no sales or assembly history (no inventory movements), and you can't convert to a bundle or kit without at least one component. If a product already has movement history, create a separate SKU instead of changing its type. See Convert & auto-detect product types.
Kit availability: Pre-built vs buildable
Because a kit can be satisfied two ways, "how many can I sell?" has two answers at any given warehouse: how many are already built (kit on-hand) and how many could be assembled from component stock. KitAvailabilityService answers both, per warehouse, and always tells you the bottleneck — the single component that limits how many kits you could build.
Buildable-from-components is computed as the minimum, across every flattened component, of component available ÷ quantity required per kit. The component that produces that minimum is surfaced as the bottleneck component, so you know exactly what to reorder or restock to build more.
There are two deliberately separate sources for these numbers, and the difference matters:
- For display (
forDisplay()) reads the fast inventory cache (products_inventory). It's what powers on-screen availability at SKU selection — quick, good enough to inform a decision, but a cached snapshot. - Live buildable (
liveBuildableQuantity()) reads authoritative on-hand availability under row locks and must run inside a database transaction. This is the number used to actually gate a real assembly, so two people can't both consume the same loose components at once.
Never treat the cached display number as a guarantee that an assembly will succeed — the live check under lock is what commits stock. Kit on-hand and buildable-from-components are independent: a kit with zero pre-built stock can still be sellable if its components are in stock, and vice versa.
Not the same as the Workshop's buildable count. The Workshop shows a
buildable_quantitythat looks only at a kit's direct components — it doesn't flatten nested kits.KitAvailabilityServicedoes flatten. Expect the two to differ when a kit contains another kit.
Flattened components: Recursive nested-kit expansion
A kit can contain another kit, which can contain another kit. To answer any real question about stock — availability, forecasting demand, potential inventory — SKU.io flattens the whole tree down to leaf standard products, multiplying quantities through each level.
Consider Kit A that contains Kit B with quantity 2, and Kit B contains Component X with quantity 3. Flattening A yields Component X at effective quantity 6 (2 × 3). The rules the flattener follows:
- Quantities multiply down the hierarchy. Each level's required quantity is multiplied by the accumulated quantity of its parents.
- Only kits recurse. A standard component is added directly at its effective quantity; a kit component is expanded into its own leaves. (Bundles never appear here — they're disallowed as components.)
- Duplicate leaves merge. If the same standard product is reached through more than one path in the tree, its quantities are summed into a single entry.
- Circular references are safe. A
visitedset guards against a kit that (mistakenly) contains itself directly or indirectly — the revisited node contributes nothing rather than looping forever.
This flattened view is what availability, potential-inventory, and forecasting all build on. For the exact pivot fields behind each component link, see the Kit & bundle component reference.
Seam: Assembly and manufacturing
Assembling a kit from components — the physical build that turns loose stock into a finished kit — belongs to the assembly / manufacturing area, not the catalog. This page defines what a kit is; the assembly flow documents how you build one.
Two bridges connect kit definitions to assembly:
- Auto-created phantom BOM. When the Manufacturing module needs to service a legacy assembly request, it mirrors a kit's
product_componentsinto a phantom Bill of Materials so the same assembly engine can handle both legacy kits and modern BOMs. This requires an EACH unit of measure to exist and requires the kit to have at least one component — a kit with no components can't produce a BOM. - Browse kits for assembly. The assembly form lists kit products with a per-warehouse
qty_on_hand(pre-built) andqty_possible(buildable from direct components). Note that without a warehouse selected, both quantities return 0 — you must pick a warehouse to see real numbers, and like the Workshop this count looks at direct components only.
For the assembly workflow itself — building, consuming components, and recording the finished kit — see the Inventory guide, which also covers stock quantities, FIFO layers, and COGS for both the kit and its components.
Seam: Demand forecasting
When forecasting projects demand, it needs to push a kit's demand down onto the components that actually get consumed. It does this with its own flattening pass: a recursive expansion (bounded to a depth of 10 levels) that writes flattened kit-component relationships into a temporary table so demand can be attributed to leaf components across a whole forecast build.
This lives in the Demand Planning / Forecasting area — the catalog only defines the kit structure that forecasting reads. For how kit demand feeds reorder suggestions, see the Inventory guide.
Made-to-order / decorated goods (not yet built)
A separate made-to-order workflow — for decorated or personalized goods, where each sales-order line carries its own artwork and decoration spec, and blanks are routed to a decorator through manufacturing with layered blank-plus-decoration costing — is currently a draft proposal only. None of those models exist in the product yet.
Don't treat made-to-order as a shipped capability. If you need to sell configurable or assembled goods today, use kits (stock or assemble) and bundles (virtual grouping) as described above. This note will be replaced with a real guide when the feature lands.
Next steps
- Build bundles & kits in the Workshop — create and edit the component list.
- Bundle pricing & revenue proration — how a bundle's price splits across components.
- Product types explained — how all six product types behave.
- Kit & bundle component reference — component fields, quantities, and guards.
- Convert & auto-detect product types — the rules for changing a product's type.