Skip to content
ERP Builders
ERP Development

Odoo Custom Module Development: Practices That Last

How to build Odoo custom modules that survive upgrades: inheritance, module structure, security, testing, performance and code review practices.

By ERP Builders Architecture Group2 min read

Odoo makes it easy to customise. That's the problem. A developer can add a field, override a method and patch a view in an afternoon. Do that fifty times without discipline and you end up with a system nobody can upgrade.

Here's how we build Odoo modules so they're still maintainable three versions later.

Rule 1: Extend, never edit

Never edit files in Odoo's core or in third-party modules. Create your own module and use inheritance:

from odoo import api, fields, models


class SaleOrder(models.Model):
    _inherit = "sale.order"

    delivery_window = fields.Selection(
        [("am", "Morning"), ("pm", "Afternoon")],
        string="Delivery window",
    )

    @api.constrains("delivery_window", "commitment_date")
    def _check_delivery_window(self):
        for order in self:
            if order.delivery_window and not order.commitment_date:
                raise models.ValidationError(
                    "Set a delivery date before choosing a delivery window."
                )

Views get the same treatment, with XPath to add or move elements rather than replacing whole views.

Rule 2: Call super, almost always

When overriding a method, call super() and add behaviour before or after it. Replacing a standard method entirely means you silently lose every fix Odoo makes to it.

Rule 3: Small modules with one purpose

sale_delivery_window is better than company_customisations. Small modules are easier to test, port, disable and explain. Name them by what they do.

Rule 4: Structure consistently

sale_delivery_window/
  __init__.py
  __manifest__.py
  models/
  views/
  security/ir.model.access.csv
  data/
  tests/
  README.rst

Every module gets a README saying what it does, why it exists and who asked for it.

Rule 5: Security from the start

  • Access rights (ir.model.access.csv) for every new model
  • Record rules where users should see only some records
  • Never use sudo() to get around a permission problem without understanding it
  • Validate input in controllers, especially public ones

Rule 6: Mind performance

  • Avoid database queries inside loops. Use read_group, search_read or batch operations.
  • Store computed fields only when you need to search or group by them
  • Add indexes on fields you search frequently
  • Use background jobs for heavy work, not request-time processing

Rule 7: Write tests

At minimum, test the business rule your module introduces. Odoo's test framework runs tests on install. Run them in CI on every commit.

Rule 8: Version control and review

  • Every module in Git, with a branch per feature
  • Code review before merging
  • Pre-commit hooks for formatting and linting (the OCA's configuration is a good starting point)
  • Deploy to staging, test, then production

Rule 9: Keep a customisation register

A simple table: module, purpose, requester, date, which standard behaviour it changes. It makes upgrades and audits much easier.

When not to write a module

  • Standard configuration can do it
  • A process change would remove the need
  • Studio can handle it (on Enterprise), for simple fields and views
  • A well-maintained OCA module already does it

See Odoo Studio vs custom development for where that line falls. Our Odoo development team follows these practices on every project.

Frequently asked questions

What language are Odoo modules written in?

Python for models and business logic, XML for views and data, and JavaScript (the OWL framework) for front-end components.

Should we edit Odoo's core code?

No. Always extend through separate modules using inheritance. Core edits are lost or conflict at every update.

ERP Builders Architecture Group

The engineers responsible for integration design, data migration tooling and performance work across ERP Builders projects.

Related articles

ERP Development3 min read

Odoo 20 Access Rights: Migrating to ir.access

Odoo 20 removes record rules and merges them into access rights with domains. What changed, how to migrate ir.model.access.csv and ir.rule, and what to test.

Next step

Turn the plan into a working system.

Book a consultation with an ERP consultant. No sales script — just an honest look at your situation.