Skip to Content

Odoo Development Environment: Best Practices for Building Custom Modules

November 5, 2026 by
Odoo Development Environment: Best Practices for Building Custom Modules
Sales

Odoo Development Environment: Best Practices for Building Custom Modules

Odoo is a powerful and highly customizable ERP platform that allows businesses to adapt standard applications to their specific processes. When standard Odoo functionality is not enough, developers can create custom modules to introduce new business logic, fields, workflows, reports, integrations, and user interfaces.

However, successful Odoo development is not simply about writing Python and XML code. A well-built custom module should be secure, maintainable, upgrade-friendly, testable, performant, and easy for other developers to understand.

A properly configured development environment plays an important role in achieving these goals.

Odoo's modular architecture allows developers to extend existing applications or create entirely new applications using the Odoo framework. Its developer documentation provides dedicated guidance for module structure, ORM development, security, testing, views, controllers, and coding standards. 

This guide explains the best practices businesses and Odoo developers should follow when building custom modules.

What Is an Odoo Custom Module?

An Odoo custom module is an independent package that extends or introduces functionality within an Odoo database.

A custom module can:

  • Create new business models

  • Add fields to existing models

  • Modify existing workflows

  • Create new menus and views

  • Add reports

  • Implement automated processes

  • Create website functionality

  • Add API integrations

  • Extend existing Odoo applications

  • Introduce custom security rules

  • Add JavaScript and frontend functionality

For example, a manufacturing company might need a Production Approval module that adds an additional approval step before a Manufacturing Order can be confirmed.

Instead of modifying Odoo's core source code, developers can create a custom module that extends the existing Manufacturing application.

This approach keeps custom functionality separated from the standard Odoo codebase.

Why a Proper Odoo Development Environment Matters

A development environment provides a safe place to build and test customizations before they reach production.

Without a proper development process, developers may accidentally:

  • Modify production data

  • Break existing workflows

  • Introduce security vulnerabilities

  • Create incompatible customizations

  • Make upgrades difficult

  • Introduce performance problems

  • Lose source-code changes

  • Deploy untested functionality

A good Odoo development environment should therefore separate:

Development → Testing → Staging → Production

Developers should build and test changes before deploying them to the live system.

Recommended Odoo Development Environment

A typical professional Odoo development environment can include:

ComponentPurpose
Odoo Source CodeApplication framework
PythonBackend development
PostgreSQLDatabase
GitSource-code management
IDE/Code EditorDevelopment
Virtual EnvironmentPython dependency isolation
Testing DatabaseFunctional testing
Staging EnvironmentPre-production validation
Production EnvironmentLive ERP system

Depending on the project, developers may also use:

  • Docker

  • Linux

  • Odoo.sh

  • CI/CD pipelines

  • Automated testing

  • PostgreSQL administration tools

  • Debugging tools

Odoo's developer tutorials include guidance for running the server, enabling developer mode, using Git, Python debugging, and PostgreSQL administration tools. 

1. Keep Development, Staging, and Production Separate

One of the most important practices is to avoid developing directly on the production server.

A recommended architecture is:

Development

Used by developers to:

  • Write code

  • Create models

  • Modify views

  • Test features

  • Debug errors

Staging

Used to:

  • Test the complete module

  • Validate integrations

  • Test realistic workflows

  • Perform user acceptance testing

Production

Used only for:

  • Live business operations

  • Approved releases

  • Production data

A simplified workflow is:

Developer → Git → Testing → Staging → Approval → Production

This significantly reduces the risk of deploying unfinished code.

2. Use Git for Odoo Development

Every serious Odoo customization project should use version control.

Git allows developers to track:

  • Code changes

  • New features

  • Bug fixes

  • Configuration changes

  • Module versions

  • Developer contributions

A typical workflow might be:

main
│
├── develop
│   ├── feature/customer-approval
│   ├── feature/custom-report
│   └── fix/inventory-validation
│
└── release

Developers can create separate branches for individual features and merge them after testing.

Benefits of Git

Git helps teams:

  • Track changes

  • Review code

  • Revert mistakes

  • Collaborate

  • Maintain release history

  • Identify when bugs were introduced

It is particularly valuable for large Odoo projects where multiple developers work on the same custom modules.

3. Follow a Standard Odoo Module Structure

A custom module should have a clear and predictable structure.

For example:

custom_sales_extension/
│
├── __init__.py
├── __manifest__.py
│
├── models/
│   ├── __init__.py
│   └── sale_order.py
│
├── views/
│   ├── sale_order_views.xml
│   └── menu_views.xml
│
├── security/
│   ├── ir.model.access.csv
│   └── security.xml
│
├── data/
│   └── data.xml
│
├── wizard/
│   ├── __init__.py
│   └── approval_wizard.py
│
├── report/
│   └── sale_report.xml
│
├── static/
│   ├── src/
│   └── tests/
│
└── tests/
    ├── __init__.py
    └── test_sale_order.py

Odoo's coding guidelines recommend organizing module functionality into directories such as models, controllers, views, data, static, wizard, report, and tests where appropriate. 

A clean structure makes the module easier to understand, debug, maintain, and upgrade.

4. Maintain a Proper __manifest__.py

The __manifest__.py file defines important metadata about an Odoo module.

It can specify:

  • Module name

  • Version

  • Dependencies

  • Author

  • Category

  • Description

  • Data files

  • Demo files

  • Assets

  • Installation behavior

A simple example is:

{
    'name': 'Custom Sales Extension',
    'version': '1.0',
    'depends': ['sale'],
    'category': 'Sales',
    'description': 'Custom sales functionality',
    'data': [
        'security/ir.model.access.csv',
        'views/sale_order_views.xml',
    ],
    'installable': True,
}

Odoo documentation specifies that __manifest__.py declares a Python package as an Odoo module and defines its metadata and dependencies. Dependencies are loaded before the module itself. 

Best Practice

Keep dependencies minimal.

If your module only requires sale, avoid unnecessarily depending on several unrelated applications.

This reduces coupling and can make upgrades easier.

5. Use the Odoo ORM Properly

The Object-Relational Mapping (ORM) layer is one of the most important parts of Odoo development.

Instead of directly manipulating database tables, developers generally interact with Odoo models through the ORM.

For example:

orders = self.env['sale.order'].search([
    ('state', '=', 'sale')
])

The ORM handles important Odoo behaviors including:

  • Access rights

  • Record rules

  • Field behavior

  • Relationships

  • Computed fields

  • Caching

  • Database operations

Odoo's security documentation specifically warns against bypassing the ORM when it can perform the required operation, because direct database access can bypass important framework behavior and security mechanisms. 

6. Avoid Unnecessary Raw SQL

Direct SQL should not be the first solution when the Odoo ORM can handle the requirement.

Avoid patterns such as:

self.env.cr.execute(...)

unless there is a genuine technical reason to use SQL.

Prefer ORM methods such as:

search()
create()
write()
unlink()
read()
browse()

For example:

customers = self.env['res.partner'].search([
    ('customer_rank', '>', 0)
])

This is generally easier to maintain and works with Odoo's security and framework mechanisms.

Odoo's security documentation explicitly recommends using the ORM rather than bypassing it with direct database cursor operations whenever possible. 

7. Design Models Carefully

Before writing Python code, developers should understand the business requirement and design the model structure.

Consider:

Model

custom.approval

Fields

name
user_id
approval_date
state
notes

States

Draft
Submitted
Approved
Rejected

Good model design helps prevent unnecessary complexity later.

Developers should also consider:

  • Field types

  • Relationships

  • Required fields

  • Default values

  • Computed fields

  • Stored fields

  • Constraints

  • Access permissions

8. Use Inheritance Instead of Modifying Odoo Core

One of the most important Odoo development principles is to extend existing models rather than modify the Odoo core code directly.

For example:

from odoo import models, fields

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

    customer_reference = fields.Char(
        string='Customer Reference'
    )

This extends the existing Sales Order model.

It is preferable to modifying the original Odoo source file.

Why?

Core modifications can:

  • Make upgrades difficult

  • Create conflicts

  • Complicate debugging

  • Make maintenance expensive

  • Increase technical debt

Custom modules provide a cleaner separation between standard Odoo functionality and business-specific requirements.

9. Keep Business Logic in Python

Complex business logic should generally be implemented in models rather than hidden inside XML views or JavaScript.

For example:

def action_approve(self):
    for record in self:
        if not record.user_id:
            raise UserError(
                "An approver must be assigned."
            )

        record.state = 'approved'

This makes the logic reusable from:

  • Forms

  • Automated actions

  • Other Python methods

  • APIs

  • Scheduled operations

It also makes the business process easier to test.

10. Keep Views Clean and Maintainable

Odoo views are commonly defined using XML.

For example:

<record id="view_custom_approval_form" model="ir.ui.view">
    <field name="name">custom.approval.form</field>
    <field name="model">custom.approval</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <group>
                    <field name="name"/>
                    <field name="user_id"/>
                    <field name="state"/>
                </group>
            </sheet>
        </form>
    </field>
</record>

Good XML should be:

  • Structured

  • Readable

  • Consistently named

  • Easy to inherit

  • Free from unnecessary duplication

Avoid putting excessive business logic into the user interface.

11. Implement Security from the Beginning

Security should not be added at the end of the development process.

Odoo provides mechanisms including:

  • User groups

  • Access Control Lists

  • Record rules

  • Field-level restrictions

Access rights determine whether users can:

  • Read

  • Create

  • Write

  • Delete

records for a model.

These permissions are commonly defined using ir.model.access.csv. 

For example:

Sales User
    ↓
Read + Create

Sales Manager
    ↓
Read + Create + Write + Delete

Developers should test the module using different user roles rather than testing only as Administrator.

12. Never Assume Hidden Fields Mean Security

A field being invisible in a view does not automatically mean the underlying data is protected.

Security should be implemented using:

  • Access rights

  • Record rules

  • Groups

  • Field-level restrictions where appropriate

Odoo's security documentation distinguishes between visibility and actual access control and explains that field restrictions can be applied using the field's groups attribute. 

This is particularly important when developing modules containing:

  • Financial information

  • Employee information

  • Customer data

  • Pricing

  • Confidential documents

  • Management approvals

13. Be Careful With sudo()

The sudo() method can bypass normal access rights and record rules.

For example:

records = self.env['sale.order'].sudo().search([])

Although this can be useful in specific situations, it should not be used simply to make access errors disappear.

Odoo documentation warns that bypassing security mechanisms should be done carefully and only when the operation legitimately requires it. 

Before using sudo(), ask:

Should this operation really bypass the current user's permissions?

If the answer is no, fix the underlying access configuration instead.

14. Follow Odoo Coding Guidelines

Consistent coding style makes custom modules easier to maintain.

Odoo's official coding guidelines are designed to improve:

  • Readability

  • Maintainability

  • Debugging

  • Reliability

  • Code quality

  • Complexity management

The guidelines apply to new modules and new development. 

Developers should maintain consistent:

  • File names

  • Class names

  • Method names

  • Variable names

  • XML IDs

  • Module structure

  • Python formatting

For community modules, Odoo also recommends using a company or organization prefix in the module name to reduce naming conflicts. 

15. Write Automated Tests

Testing should be part of the development process, not something performed only after development is complete.

Odoo supports different types of tests, including:

  • Python unit tests

  • JavaScript tests

  • Integration tests and tours

Odoo's testing documentation describes these approaches and provides a framework for implementing module tests. 

A module might contain:

tests/
├── __init__.py
├── test_approval.py
└── test_security.py

Tests can verify scenarios such as:

  • Approval workflow

  • Calculations

  • Access permissions

  • Record creation

  • Business constraints

  • Automated actions

16. Test Business Scenarios, Not Just Code

A common mistake is testing only whether a Python method executes successfully.

Instead, test the actual business process.

For example, for a custom purchase approval module:

Scenario 1

Purchase Order below ₹50,000.

Expected: No management approval required.

Scenario 2

Purchase Order above ₹50,000.

Expected: Manager approval required.

Scenario 3

Unauthorized user attempts approval.

Expected: Access denied.

Scenario 4

Approved order is modified.

Expected: Approval workflow behaves according to business rules.

This approach produces more useful tests.

Odoo's testing guidance recommends focusing business-module tests on business flows rather than unnecessarily testing framework functionality that is already covered by Odoo itself. 

17. Consider Performance From the Beginning

Poorly designed custom modules can slow down an Odoo database.

Common performance problems include:

  • Excessive database queries

  • Searching inside loops

  • Unnecessary computed fields

  • Poorly designed domains

  • Excessive use of sudo()

  • Large unoptimized reports

  • Inefficient SQL

  • Loading unnecessary records

For example, avoid repeatedly performing searches inside a large loop when records can be retrieved more efficiently.

Instead of thinking:

"Does this code work?"

developers should also ask:

"How will this behave with 10 records, 10,000 records, or 1 million records?"

Performance becomes particularly important for:

  • Inventory

  • Accounting

  • Manufacturing

  • Sales

  • Large customer databases

  • High-volume integrations

18. Keep Customizations Modular

Avoid creating one giant custom module containing every customization.

For example, instead of:

company_customization

containing 100 unrelated features, consider separating functionality:

company_sales
company_inventory
company_manufacturing
company_accounting
company_hr

This makes it easier to:

  • Maintain features

  • Test changes

  • Deploy updates

  • Identify dependencies

  • Remove obsolete functionality

Modularity is one of the fundamental strengths of Odoo's architecture.

19. Document Custom Modules

Every custom module should have documentation.

At minimum, document:

  • Purpose

  • Business requirements

  • Dependencies

  • Installation instructions

  • Configuration

  • User roles

  • Important workflows

  • External integrations

  • Scheduled actions

  • Known limitations

For example:

Module:
Custom Purchase Approval

Purpose:
Adds approval workflow for purchase orders above
configured thresholds.

Dependencies:
purchase

User Roles:
Purchase User
Purchase Manager

Approval Rule:
> ₹50,000 → Manager Approval
> ₹250,000 → Director Approval

Documentation can save significant time when another developer needs to maintain the module later.

20. Use Meaningful XML IDs

XML IDs should be descriptive.

Prefer:

view_custom_approval_form
action_custom_approval
menu_custom_approval

instead of:

view1
action1
menu1

Meaningful IDs make debugging and module inheritance easier.

21. Avoid Hard-Coding Business Values

Instead of writing:

if amount > 50000:

consider making the threshold configurable.

For example:

Purchase Approval Limit
₹50,000

This allows administrators to change the business rule without modifying source code.

Configurable values can be managed through appropriate Odoo configuration mechanisms depending on the requirement.

22. Use Developer Mode Carefully

Developer mode is extremely useful during development.

It provides access to technical information such as:

  • Models

  • Fields

  • Views

  • Actions

  • Menus

  • External IDs

  • Technical settings

Developers can use it to understand how standard Odoo applications work before extending them.

However, technical settings should be restricted to appropriate users in production environments.

23. Debug Systematically

When an Odoo customization fails, developers should identify the problem systematically.

A useful process is:

Reproduce the Error

↓

Read the Server Log

↓

Identify the Model / View / Method

↓

Check Dependencies

↓

Check Access Rights

↓

Check Data

↓

Fix the Root Cause

↓

Run Tests

↓

Deploy to Staging

Avoid repeatedly making random changes until the error disappears.

24. Keep Dependencies Under Control

The more modules your custom module depends on, the more tightly coupled it becomes to the Odoo environment.

For example:

'depends': [
    'sale',
    'stock',
    'purchase',
]

Only include dependencies that are actually required.

Odoo installs dependencies before the dependent module, so dependency definitions directly influence module loading and installation behavior. 

25. Prepare for Odoo Upgrades

Custom modules should be developed with future upgrades in mind.

Avoid unnecessary modifications to:

  • Odoo core files

  • Standard JavaScript

  • Standard views

  • Standard workflows

Instead, use supported extension mechanisms such as:

  • Model inheritance

  • View inheritance

  • Extension modules

  • Configuration

  • Standard APIs

A customization that works today but prevents a future Odoo upgrade can become expensive technical debt.

26. Recommended Custom Module Development Workflow

A professional Odoo development process can look like this:

Step 1: Understand the Requirement

Document:

  • Business problem

  • Users

  • Workflow

  • Expected result

  • Exceptions

Step 2: Check Standard Odoo

Before writing custom code, determine whether the requirement can be solved through:

  • Configuration

  • Studio

  • Existing Odoo functionality

  • Automated actions

  • Standard modules

Step 3: Design the Solution

Define:

  • Models

  • Fields

  • Views

  • Security

  • Workflow

  • Dependencies

Step 4: Create the Module

Build the module using Odoo's standard structure.

Step 5: Implement Business Logic

Use Python and the ORM.

Step 6: Implement the UI

Create XML views, menus, actions, and required frontend components.

Step 7: Configure Security

Add access rights and record rules.

Step 8: Write Tests

Test the important business scenarios.

Step 9: Code Review

Review:

  • Security

  • Performance

  • Naming

  • Maintainability

  • Dependencies

Step 10: Deploy to Staging

Test with realistic data and workflows.

Step 11: User Acceptance Testing

Allow business users to validate the functionality.

Step 12: Production Deployment

Deploy only after approval and backup.

Example: Custom Odoo Customer Approval Module

Consider a company that wants every new customer to be approved before salespeople can confirm quotations.

Standard Odoo

Salespeople can create customers and quotations.

Business Requirement

New customers must be approved by a Sales Manager.

Custom Module

The module introduces:

Customer Status

Draft
    ↓
Submitted
    ↓
Approved
    ↓
Rejected

Additional Features

The module could add:

  • Approval button

  • Rejection button

  • Approval date

  • Approver

  • Rejection reason

  • Customer approval status

  • Sales restrictions

Security

Sales users:

  • Create customer

  • Submit for approval

  • View approval status

Sales managers:

  • Approve

  • Reject

  • Modify approval information

Testing

Tests verify:

  • Customer creation

  • Submission

  • Approval

  • Rejection

  • Unauthorized approval

  • Sales restriction

This is a good example of where a custom module can extend standard Odoo functionality without modifying the core system.

Common Odoo Development Mistakes

1. Modifying Odoo Core

This creates upgrade and maintenance problems.

Better: Use custom modules and inheritance.

2. Ignoring Security

A feature may work correctly for an Administrator but expose data to normal users.

Better: Design and test access controls from the beginning.

3. Excessive sudo()

Using sudo() everywhere can unintentionally bypass security.

Better: Use it only when there is a legitimate business reason.

4. Using Raw SQL Unnecessarily

Direct SQL can bypass important Odoo mechanisms.

Better: Use the ORM whenever practical.

5. No Automated Tests

Untested customizations are more likely to break after changes or upgrades.

Better: Add tests for important business workflows.

6. Poor Module Structure

Disorganized files make future maintenance difficult.

Better: Follow Odoo's recommended module structure.

7. Hard-Coding Business Rules

Business requirements often change.

Better: Make appropriate values configurable.

8. Testing Only as Administrator

Administrator access can hide security problems.

Better: Test with realistic user roles.

9. No Documentation

Future developers may not understand why a customization exists.

Better: Document the business purpose and technical design.

Odoo Custom Development Best Practices Checklist

Before deploying a custom module, verify:

  • Requirement is clearly documented

  • Standard Odoo functionality has been evaluated

  • Module has a clean structure

  • __manifest__.py is correctly configured

  • Dependencies are minimal

  • Odoo ORM is used appropriately

  • Core files are not unnecessarily modified

  • Access rights are configured

  • Record rules are reviewed

  • sudo() is used only when justified

  • Views are clean and maintainable

  • Business logic is separated from UI

  • Automated tests are included

  • Performance has been considered

  • Git version control is used

  • Documentation is available

  • Staging testing is completed

  • User acceptance testing is completed

  • Production backup is available

  • Deployment and rollback procedures are defined

Benefits of Following Odoo Development Best Practices

A disciplined development approach provides long-term benefits.

Better Code Quality

Developers can understand and maintain the code more easily.

Improved Security

Users receive only the access they need.

Easier Upgrades

Custom functionality remains separated from standard Odoo code.

Better Performance

Efficient ORM usage and optimized business logic reduce unnecessary database operations.

Faster Troubleshooting

Clear structure and documentation make problems easier to identify.

Easier Team Collaboration

Git, consistent naming, and modular architecture allow multiple developers to work together effectively.

Lower Technical Debt

Well-designed custom modules are easier to maintain as the business grows.

How ERP Harbor Consulting Services Can Help

Custom Odoo development should focus on solving business problems while keeping the resulting solution maintainable and upgrade-friendly.

ERP Harbor Consulting Services can help businesses with:

  • Odoo custom module development

  • Odoo customization

  • Odoo application development

  • Python development

  • XML and view customization

  • JavaScript/frontend customization

  • Odoo API integrations

  • Third-party integrations

  • Workflow automation

  • Manufacturing customization

  • Inventory customization

  • Sales and Purchase customization

  • Accounting customization

  • Reporting and dashboards

  • Odoo migration and upgrades

  • Performance optimization

  • Testing and debugging

  • Odoo maintenance and support

Our development approach focuses on understanding the business requirement first, evaluating standard Odoo functionality, and then building custom functionality where it provides genuine business value.

Conclusion

Building an Odoo custom module is more than adding a few Python models or modifying an XML view. A successful customization requires a well-structured development environment, clean architecture, secure access control, proper ORM usage, automated testing, version control, performance considerations, and upgrade-friendly design.

Odoo's modular architecture makes it possible to extend the ERP without unnecessarily modifying the core platform. By following official development guidelines and adopting professional development practices, businesses can create custom modules that remain reliable as their operations and Odoo environment evolve. 

The goal should not simply be to make a customization work today.

The goal should be to build an Odoo solution that is secure, maintainable, scalable, testable, and ready for the future.

How to Build Custom Dashboards in Odoo