Ad – 728×90
⚡ 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
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.

Ad – 728×90

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

Frequently Asked Questions

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.