All posts
Integrator10 min read

Odoo product variants and the configurator: templates, attributes, and pricelist combinations

Odoo models configurable products through templates and variants. Understanding how attributes, values, and exclusions interact - and how pricelists and BOMs key off variants - is essential before you build any product catalog with more than a handful of SKUs.

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_ids entry 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 extras

If 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.value

Querying a variant's attribute values:

python
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:

python
template = self.env['product.template'].browse(tmpl_id)
variants = template.product_variant_ids  # product.product recordset

Computing the sale price for a variant (combining template price + extras):

python
# 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 + extras

Common mistakes summary#

MistakeEffectFix
Using "Instantly" mode for high-combination products500+ variants created immediately, UI slows downSwitch to "Dynamically" before adding more values
Forgetting to set price extrasAll variants have the same priceAdd extras on each attribute value line
Pricelist rule on template when variant-specific rule neededWrong price appliedChange rule's "Apply On" to the specific variant
No variant exclusions for impossible combinationsOrders placed for unavailable combinationsAdd exclusions on the template
Single BOM for multi-variant productWrong components picked for manufacturingUse component-level "Apply on Variants" fields
Reorder rules set on template, not variantsReplenishment does not distinguish sizes/colorsSet 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.

Try ERPeek on your own Odoo module - ask questions, scaffold tests, and explore your codebase in plain language.

Get started free