When a company sells T-shirts in three colors and four sizes, they have one product logically but twelve distinct SKUs. When they sell custom computers with a processor, RAM, and storage choice, they have a configurable product with potentially hundreds of combinations - but not all combinations are valid or stocked.
Odoo models this through product templates and product variants. The template is the shared definition (name, description, price logic, BOM structure). Each variant is one specific combination of attribute values (Color: Red + Size: M). This post covers how to configure the template-variant relationship correctly, where the configurator fits in, how pricelists work with variants, and the most common mistakes that produce duplicate products or pricing errors.
Product template vs. product variant#
product.template is the parent record. It stores everything shared:
- Name, description, internal reference (base)
- Sale price (default before any variant-specific override)
- Cost
- Taxes and fiscal positions
- Route and procurement rules
- BOM structure (in manufacturing - the BOM can be variant-specific via "Apply on Variants")
- Images (main image + variant images)
product.product is a specific variant. It extends the template with:
- A unique combination of attribute values (Color: Blue, Size: L)
- Its own
default_code(internal reference, usually template ref + variant suffix) - Its own barcode
- Its own cost (optional override)
- Its own stock (each variant has independent inventory)
The relationship is strict many-to-one: every product.product belongs to exactly one product.template. A template with no attributes has exactly one variant (the "base variant"). When you add attributes with values, Odoo creates one variant per combination unless you configure exclusions.
Attributes and attribute values#
Creating attributes#
Inventory → Configuration → Attributes (or Sales → Configuration → Attributes depending on modules installed).
Each attribute has:
- Name: "Color", "Size", "RAM"
- Display Type: Radio (one choice, mutually exclusive), Select (dropdown), Color (colored swatches), Multi-Checkbox (multiple values allowed - for configurator only, not used for standard variants)
- Variants Creation: the critical field. Three modes:
- Instantly - create all variant combinations as soon as values are added to the template. Best for simple products where all combinations exist and should have their own inventory record.
- Dynamically - create the variant only when it is first added to a sale order or purchase order. Good for products where most combinations are theoretically possible but most are never ordered.
- Never (attribute prices only) - do not create variants at all. Use the attribute to adjust the price (e.g., a size surcharge) without creating separate stock records. Good for products where "size" affects price but not inventory.
Choosing the wrong Variants Creation mode is the most common setup mistake. A company with 10 colors × 5 sizes × 3 materials = 150 variants does not want Instantly mode unless they stock all 150 separately.
Adding attributes to a template#
On the product template form, the Attributes & Variants tab shows the attribute-value matrix. Add an attribute, then select which values apply to this product. Odoo shows the current variant count - that number multiplied by your storage requirements tells you whether your mode choice is sane.
Attribute value extras#
Each attribute value on a product can carry:
- Sales Price Extra: the amount added to the template price for this combination. If "Blue" adds €5 and "XL" adds €3, the "Blue XL" variant is template price + €8.
- Is Custom: checking this marks the value as requiring a custom text entry at sale time (e.g., "Print your name: ___"). The SO line will carry a
product_custom_attribute_value_idsentry with the customer-entered text.
Variant exclusions#
Not all combinations make sense. Odoo has a variant exclusion mechanism on the template Attributes & Variants tab: "Exclude" links. You can say "if Color = White, then Size cannot be XXL" (maybe you only stock certain sizes in white).
Exclusions remove the specified variant combinations from creation. The excluded combinations do not appear in the configurator or in the product variant list.
For complex exclusion logic (many attributes, many exclusions), maintain a spreadsheet of valid combinations before configuring Odoo - it is much harder to undo variant creation than to plan it correctly upfront.
The product configurator#
The configurator is the UI that appears on sale order lines when a customer (or salesperson) selects a configurable product. It presents each attribute as a control (radio buttons, dropdowns, swatches) and updates the price in real time as choices are made.
Enable it at Sales → Configuration → Settings → Product Catalog → Variants → Product Configurator.
The configurator respects:
- Attribute display types (radio, select, color)
- Exclusions (grays out invalid combinations)
- Custom values (shows a text input)
- Price extras (shows the incremental price change per selection)
When the configurator does not appear: if the product template has only one valid variant (either no attributes, or all attributes are "Never" mode), the configurator is skipped and the variant is selected directly. The configurator appears only when there is a genuine choice to make.
Pricelists and variants#
Pricelists (Sales → Catalogs → Pricelists) can be scoped to specific variants in two ways:
Pricelist rule on a variant#
When adding a pricelist rule, set the "Apply On" field to "Product Variant" and select the specific variant. The rule applies only when that exact variant is ordered. Use this for variant-specific promotions ("Size M is on sale this week").
Pricelist rule on a template#
Set "Apply On" to "Product Template." The rule applies to all variants of that template. Combined with attribute price extras, the final line price is:
Final Price = Pricelist rule price + attribute extrasIf the pricelist uses a percentage discount from the sale price, the base is the template's sale price before extras. Extras are added after the discount.
Common pricelist + variant mistake#
A pricelist rule set to a specific variant is not applied when the same product.template (without variant specification) is ordered. If you set a rule for "T-Shirt / Blue / M" but a sales rep orders "T-Shirt" without specifying the variant (impossible with the configurator enabled, but possible via programmatic SO creation), the rule does not fire. Always check that pricelist rules reference the correct product level (template vs. variant).
BOMs and variants (manufacturing)#
In manufacturing, BOMs can be variant-specific using the "Apply on Variants" field on the BOM header. Leave it blank for a BOM that applies to all variants; fill it with specific attribute-value combinations to create variant-specific BOMs.
Example: a chair comes in wood or metal frame. The BOM for "Chair / Wood Frame" has timber components; the BOM for "Chair / Metal Frame" has steel tube components. Both templates share the same labor routing and packaging materials.
For complex variant-BOM relationships, use component variants: on a BOM line, the "Apply on Variants" field restricts that component to specific variants. A common pattern:
- BOM line: "Oak timber" - Apply on Variants: Wood Frame
- BOM line: "Steel tube" - Apply on Variants: Metal Frame
- BOM line: "Cushion" - Apply on Variants: (blank, applies to all)
This produces a single BOM that conditionally includes the right materials by variant without duplicating the entire BOM.
Inventory per variant#
Each product.product has its own quant stock. When you run inventory adjustments or receive goods, you must specify the full variant (not just the template). An inventory adjustment on "T-Shirt" without a size/color selection will fail or default to the base variant - which is rarely what you want.
Reorder rules (replenishment) are set per variant. A reorder rule on "T-Shirt / Blue / M" with min_qty=5 does not replenish "T-Shirt / Blue / L". Set reorder rules for each variant that has independent stock management.
Putaway and storage location rules in Odoo 16+ can be variant-aware: you can route "T-Shirt / Red / *" to a specific shelf location in the warehouse.
Developer notes: the data model#
product.template
└── product.template.attribute.line (one per attribute on this template)
├── attribute_id → product.attribute
└── value_ids → product.attribute.value[]
└── price_extra (the surcharge for this value on this template)
product.product (variant)
├── product_tmpl_id → product.template
└── product_template_attribute_value_ids
└── product.template.attribute.value
├── attribute_id
└── product_attribute_value_id → product.attribute.valueQuerying a variant's attribute values:
variant = self.env['product.product'].browse(variant_id)
for ptav in variant.product_template_attribute_value_ids:
print(ptav.attribute_id.name, ptav.name, ptav.price_extra)Finding all variants of a template:
template = self.env['product.template'].browse(tmpl_id)
variants = template.product_variant_ids # product.product recordsetComputing the sale price for a variant (combining template price + extras):
# Odoo does this internally via product.product._get_combination_info()
info = template._get_combination_info(
combination=variant.product_template_attribute_value_ids,
product_id=variant.id,
add_qty=1,
pricelist=pricelist,
)
# info['price'] is the final price after pricelist + extrasCommon mistakes summary#
| Mistake | Effect | Fix |
|---|---|---|
| Using "Instantly" mode for high-combination products | 500+ variants created immediately, UI slows down | Switch to "Dynamically" before adding more values |
| Forgetting to set price extras | All variants have the same price | Add extras on each attribute value line |
| Pricelist rule on template when variant-specific rule needed | Wrong price applied | Change rule's "Apply On" to the specific variant |
| No variant exclusions for impossible combinations | Orders placed for unavailable combinations | Add exclusions on the template |
| Single BOM for multi-variant product | Wrong components picked for manufacturing | Use component-level "Apply on Variants" fields |
| Reorder rules set on template, not variants | Replenishment does not distinguish sizes/colors | Set rules per variant (product.product) |
For the inventory configuration that stores variant stock, see the inventory configuration guide. For pricing strategies including pricelists, see the pricing explained guide.

