Advertisement
⚡ Advanced Topics

Odoo Multi-Company Support – company_id, company_dependent, and Record Rules

Multi-company support allows a single Odoo database to host multiple independent companies. Each user can switch between companies; records are scoped to a company or shared across companies. Building a module that works correctly in multi-company environments requires following specific patterns.

⏱️ 22 min 🎯 Advanced 📅 Updated 2026

Multi-Company: Isolating Data Between Companies

One Odoo database can host several companies. The mechanism that keeps Company A's data from leaking into Company B is the company_id field plus record rules that filter by the user's allowed companies.

class SaleOrder(models.Model):
    _inherit = "sale.order"
    # standard pattern: default to the active company
    company_id = fields.Many2one(
        "res.company", default=lambda self: self.env.company)
ConceptRole
company_id fieldtags each record with its owning company
company record rulefilters records to the user's allowed_company_ids
self.env.companythe currently active company
self.env.companiesall companies the user selected

Shared vs isolated data: some models are company-specific (orders, invoices — carry a company_id); others are shared across all companies (products, partners often are). When you add a company-specific model, include a company_id field and a matching record rule, or users will see every company's records.

The active-company gotcha: a user can have several companies enabled at once (allowed_company_ids), and self.env.company is just the primary active one. Always default new records to self.env.company and be careful with cross-company references — linking a record in Company A to one in Company B is a common source of subtle bugs. Test with a real multi-company setup.

🏋️ Practical Exercise

  1. Enable multiple companies.
  2. Add a company_id field to a model.
  3. Add a multi-company record rule.
  4. Switch the active company.
  5. Share a record across companies.

🔥 Challenge Exercise

Make a custom model multi-company aware: add a company_id field with a default and a record rule so users see only their company’s records. Explain how company_id and record rules enforce isolation and how allowed companies differ from the active company.

What you'll learn:
  • How multi-company works in Odoo: allowed_company_ids and the company switcher
  • Adding company_id to a custom model
  • company_dependent fields for per-company configuration
  • Writing record rules that enforce company isolation
  • Common multi-company pitfalls and how to avoid them

How Multi-Company Works

In a multi-company Odoo instance, each user has a primary company and a set of allowed companies. The current company context is in self.env.company and the allowed set is in self.env.companies:

Python
self.env.company        # the currently active company (res.company)
self.env.companies      # all companies the user has switched to (recordset)
self.env.company.id     # the active company ID
self.env.companies.ids  # list of allowed company IDs

When a user has multiple companies active, ORM searches automatically include records from all active companies (if record rules are set up correctly).

Adding company_id to Your Model

Use the standard company_id field name with res.company as the comodel:

Python
from odoo import models, fields

class LibraryBook(models.Model):
    _name = 'library.book'
    _description = 'Library Book'

    name = fields.Char(string='Title', required=True)

    company_id = fields.Many2one(
        'res.company',
        string='Company',
        required=True,
        default=lambda self: self.env.company,
        index=True,
    )

The default lambda self: self.env.company sets the company to the user's current active company when creating a new record.

Multi-Company Record Rules

A record rule enforces that users can only see records from their allowed companies:

XML
<record id="rule_library_book_company" model="ir.rule">
  <field name="name">Library Book: multi-company rule</field>
  <field name="model_id" ref="model_library_book"/>
  <field name="domain_force">
    ['|',
      ('company_id', '=', False),
      ('company_id', 'in', company_ids)]
  </field>
</record>

The domain ('company_id', '=', False) allows shared records (no company) to be visible to everyone. company_ids is a special variable in record rule domains that resolves to the user's allowed company IDs at evaluation time.

Advertisement

company_dependent Fields

Some configuration fields should have different values per company without duplicating records. Use company_dependent=True:

Python
class LibraryConfig(models.TransientModel):
    _inherit = 'res.config.settings'

    library_late_fee = fields.Float(
        string='Late Fee per Day',
        config_parameter='library.late_fee',
        company_dependent=True,  # each company has its own value
    )

With company_dependent=True, each company stores its own value for the field. When you read the field, Odoo automatically returns the value for self.env.company. The field type must be one of: Char, Float, Integer, Boolean, Date, Datetime, Selection, or Many2one.

Common Multi-Company Pitfalls

MistakeSymptomFix
Hardcoding company_id=1Data only works for main companyAlways use self.env.company.id
No record rule on company_idUsers see other companies' dataAdd ir.rule with company_ids domain
Forgetting | company_id=False in ruleShared configuration invisibleAlways add the False alternative
sudo() bypasses record rulesMulti-company isolation brokenAdd company filter explicitly in sudo() searches
Key takeaways:
  • Use self.env.company (not hardcoded IDs) for the current company
  • Add a company_id Many2one field with a default lambda and a matching record rule
  • Record rule domain: ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]
  • Use company_dependent=True for configuration fields that differ per company

Interview Questions

  • How does Odoo support multiple companies?
  • What field makes a model multi-company aware?
  • How is data isolated between companies?
  • What is the difference between the active company and allowed companies?
  • How do you share a record across companies?

FAQ

What's the difference between company_id and the branches feature? +

The company_id field is Odoo's core multi-company mechanism — each company is a fully independent accounting entity. Odoo 17+ introduced "branches" as a lighter-weight sub-company structure for organizations that share accounting but have different operational units. Branches use the same mechanism but with a different UX and less strict isolation.

How do I create records for a specific company from code? +

Use self.with_company(target_company).env['my.model'].create({...}). This sets the environment's company to target_company for that context. Alternatively, explicitly set 'company_id': target_company.id in the create vals. The first approach is safer as it also affects defaults of related records created during that operation.

Can a record belong to multiple companies? +

Standard records with company_id belong to one company (or none for shared records). Some models like res.partner and product.template use company_ids (Many2many) instead to allow a record to be accessible across multiple companies. Use Many2many for resources that need to be shared selectively across companies.