Every manufacturing client we onboard asks the same first question: can Odoo handle our bill of materials the way our old spreadsheet does, with sub-assemblies, phantom components and a dozen operations per routing. The honest answer is yes, but only if the Odoo manufacturing BOM is structured correctly from day one. Get the BOM wrong and every downstream number — cost, lead time, capacity — is wrong with it.
This post walks through how we set up multi-level BOMs, routings, work centers and production order costing on real projects, including the parts that trip people up.
Why the Odoo Manufacturing BOM Is the Foundation
The BOM is not just a parts list. In Odoo it drives the manufacturing order, the component reservations, the routing, and eventually the cost that lands on the finished product. A BOM with the wrong component quantities will quietly under-cost or over-cost every unit you build, and nobody notices until a margin report looks wrong months later.
We always start a manufacturing project by sitting with the production floor and the cost accountant together, not separately. The floor knows the actual operations; the accountant knows what the cost needs to roll up to. Those two views rarely match on day one, and reconciling them before configuration saves weeks of rework later.
Multi-Level BOMs: Sub-Assemblies Done Right
Most real products are not single-level. A finished chair has a frame sub-assembly, a cushion sub-assembly, and hardware. Odoo supports this natively: a BOM component can itself be a manufactured product with its own BOM, and Odoo will explode the structure as many levels deep as you need.
Two modeling choices matter here:
- Stocked sub-assembly — the sub-assembly is manufactured on its own order, stored, and then consumed by the parent BOM. Use this when the sub-assembly is also sold standalone, batch-produced ahead of demand, or needs its own quality check.
- Kit / phantom BOM — the sub-assembly line explodes directly into its own components on the parent manufacturing order, with no separate production order or stock record for the intermediate item. Use this for packaging kits or simple groupings that never exist as inventory on their own.
Mixing these two approaches on the same product tree is where we see the most confusion. If a sub-assembly sometimes needs its own work order (for a quality hold, for example) and sometimes doesn't, it should be a real stocked BOM, not a phantom one, even if that adds an extra manufacturing order to the chain.
One limitation worth naming plainly: a deep multi-level BOM makes the manufacturing order tree harder to read on the shop floor. Operators scrolling through five nested levels of components lose track of what they are actually building right now. We mitigate this by keeping routings tight at each level and training supervisors to work from the work order screen, not the raw BOM view.
Routings and Work Centers: Where Time and Cost Actually Happen
A BOM without a routing only tells you what goes into the product. The routing tells you how it gets made — which operations, in what order, at which work center, and how long each one takes. This is where Odoo Manufacturing earns its keep over a basic BOM-only setup.
Each work center in Odoo carries its own costing rate (per hour), capacity, and optionally a calendar of working hours. When a manufacturing order is confirmed, Odoo generates work orders against the routing steps, and operators can log actual time against each one from a tablet or the shop floor control panel.
A typical routing we configure for a mid-size fabrication client looks like this:
| Operation | Work Center | Expected Duration | Cost Driver |
|---|---|---|---|
| Cutting | CNC-01 | 12 min | Machine time |
| Welding | WELD-02 | 25 min | Labor + machine |
| Painting | PAINT-01 | 15 min | Labor + consumables |
| Quality Check | QC-01 | 8 min | Labor only |
The gap between expected and actual duration is one of the most useful numbers in the whole system. When actual welding time consistently runs 40 percent over the routing estimate, that is either a routing that was never updated after a process change, or a work center that needs more capacity. Either way, it is a conversation worth having, and Odoo surfaces it automatically once operators are logging real time instead of clicking through work orders without recording duration.
Tracking the Real Cost of a Production Order
This is the section most manufacturing teams actually care about, and it is also the one most often set up wrong. The cost of a manufactured product in Odoo comes from three places:
- Component cost — the valuation of every raw material and sub-assembly consumed, based on the costing method (FIFO, average, or standard) set on each product's category.
- Operation cost — work center hourly rate multiplied by actual (or planned, in standard costing) duration for each routing step.
- Overhead, if you choose to load it — some teams add a manufacturing overhead rate per hour or per unit on top of the first two, though we recommend keeping this simple at first and refining later once real data exists.
With standard costing, the production order posts the standard component and operation cost at completion, and any difference between standard and actual shows up as a variance you can review at month-end. With FIFO or average costing on the component side, the actual component cost at the moment of consumption flows into the manufacturing order, which gives a more accurate number per batch but moves around more between runs of the same product.
We lean toward standard costing for clients who need predictable product costing for quoting, and FIFO or average for clients whose raw material prices swing enough that a fixed standard would mislead the sales team. Neither is universally right; it depends on how your purchasing actually behaves.
One real trade-off: standard costing is simpler to read on a report but hides the true squeeze when input prices rise, because the variance account absorbs it rather than the product cost itself. If a procurement manager never looks at variance accounts, standard costing can quietly mask a margin problem for months.
Backflush, Manual Consumption and What Actually Gets Tracked
Odoo lets you set component consumption to backflush automatically at order completion, or require manual consumption confirmation per component with lot or serial tracking. For regulated products — food, pharma, anything with traceability requirements — manual confirmation with lot tracking is worth the extra click per component, because it gives you a genuine forward and backward trace from raw material lot to finished goods lot.
For high-volume, low-regulation assembly, automatic backflush based on the BOM quantities is faster and good enough. The trade-off is that backflush assumes the BOM quantity is exactly what was consumed; if operators routinely use slightly more material due to scrap, backflush will under-report scrap and your component stock will drift from reality until the next physical count.
Getting the First BOM Structure Right
A few practices we repeat on nearly every manufacturing engagement:
- Build the BOM tree on paper or a spreadsheet with the production supervisor before entering a single line in Odoo.
- Separate "make to stock" sub-assemblies from "make to order" ones early; it affects whether Odoo auto-generates a nested manufacturing order or reserves existing stock.
- Set routing step durations from a time study, not a guess, even a rough one with a stopwatch on the floor for a day.
- Decide the costing method per product category before go-live, not after the first month-end close has already posted numbers on the old assumption.
- Keep work center calendars current; a work center marked available 24/7 when it actually runs one shift will distort every capacity and lead-time calculation downstream.
If you are migrating from a legacy MRP system or a spreadsheet-based BOM, expect the BOM cleanup itself to take longer than the Odoo configuration. We have seen BOM data audits take three times longer than the manufacturing module setup, simply because historical BOMs accumulate dead components and stale quantities nobody has validated in years. Treat that audit as its own project phase, with its own timeline, rather than folding it quietly into "go-live week."
Our general approach for any Odoo implementation is to configure first and customize only where the standard routing and BOM tools genuinely cannot represent the real process — which, in manufacturing, is less often than most teams assume going in. If your production process does need custom logic beyond routings and work orders, that is a conversation for Odoo customization rather than a workaround bolted onto standard BOMs.
Before your next go-live, pull one finished product's full BOM tree and routing, and walk it end to end with whoever actually runs the line. If the sequence of operations on paper does not match what happens at the work center, fix the routing before go-live, not after the first variance report raises questions nobody can answer.



