Odoo's modular architecture allows developers to extend existing apps or build entirely new business capabilities from scratch. Whether you need custom tracking models, tailored automation, or unique department views, building a modular addon keeps your business logic clean, maintainable, and isolated from core files.
Tested on Odoo 18: The commands, file structure, and code samples below are tested on Odoo 18 (Community and Enterprise) and are fully compatible with Odoo 17 and Odoo 16.
Follow these concrete technical steps to build, configure, secure, and install your custom module.
Step 1: Create the Module Skeleton
Instead of creating directories and files manually, use Odoo's built-in scaffold CLI tool to generate the standard module structure:
./odoo-bin scaffold my_module /path/to/custom/addons
This creates a pre-configured directory named my_module inside your custom addons directory, complete with models, views, controllers, and demo data.
Step 2: Module Folder Structure
A streamlined, complete custom module contains the following files:
my_module/
├── __init__.py
├── __manifest__.py
├── models/
│ ├── __init__.py
│ └── models.py
├── security/
│ └── ir.model.access.csv
└── views/
└── views.xml
Step 3: Define the Manifest (__manifest__.py)
The manifest file declares your module's metadata, its dependencies, and the data files that Odoo loads upon installation.
Manifest naming note: In Odoo 9 and earlier versions, the manifest was named __openerp__.py. Modern Odoo releases (Odoo 10 through Odoo 18+) exclusively recognize __manifest__.py. Do not use __openerp__.py.
Here is a minimal, clean __manifest__.py:
# -*- coding: utf-8 -*-
{
'name': 'My Custom Module',
'version': '18.0.1.0.0',
'summary': 'Manage custom business records in Odoo',
'sequence': 10,
'category': 'Customizations',
'depends': ['base'],
'data': [
'security/ir.model.access.csv',
'views/views.xml',
],
'installable': True,
'application': True,
'license': 'LGPL-3',
}
Ensure your root __init__.py imports the models directory:
# -*- coding: utf-8 -*-
from . import models
Step 4: Create a Data Model (models/models.py)
Odoo models represent database tables, mapping Python classes directly to PostgreSQL tables through Odoo's ORM. Here is a simple model with two fields:
# -*- coding: utf-8 -*-
from odoo import models, fields
class MyCustomModel(models.Model):
_name = 'my_module.custom_model'
_description = 'My Custom Model'
name = fields.Char(string='Title', required=True)
description = fields.Text(string='Description')
Also ensure models/__init__.py imports your model file:
# -*- coding: utf-8 -*-
from . import models
Step 5: Add Security Access (security/ir.model.access.csv)
In Odoo, any model defined in Python is hidden by default. Without an explicit access control list (ACL) rule in security/ir.model.access.csv, even system administrators cannot view, create, or modify records.
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_module_custom_model_user,my_module.custom_model.user,model_my_module_custom_model,base.group_user,1,1,1,1
model_my_module_custom_model is the auto-generated XML ID for your model (with underscores replacing dots in _name). 1,1,1,1 grants full read, write, create, and delete permissions to standard internal users.
Step 6: Define Views and Menus (views/views.xml)
Views describe the user interface. We'll create a list view, a form view, a window action, and top-level navigation menus in views/views.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- List View (Odoo 18 uses <list>; earlier versions use <tree>) -->
<record id="view_my_module_list" model="ir.ui.view">
<field name="name">my_module.custom_model.list</field>
<field name="model">my_module.custom_model</field>
<field name="arch" type="xml">
<list string="Custom Records">
<field name="name"/>
<field name="description"/>
</list>
</field>
</record>
<!-- Form View -->
<record id="view_my_module_form" model="ir.ui.view">
<field name="name">my_module.custom_model.form</field>
<field name="model">my_module.custom_model</field>
<field name="arch" type="xml">
<form string="Custom Record">
<sheet>
<group>
<field name="name"/>
<field name="description"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Window Action -->
<record id="action_my_module_records" model="ir.actions.act_window">
<field name="name">Custom Records</field>
<field name="res_model">my_module.custom_model</field>
<field name="view_mode">list,form</field>
</record>
<!-- Menu Items -->
<menuitem id="menu_my_module_root" name="My Module" sequence="10"/>
<menuitem id="menu_my_module_records" name="Records" parent="menu_my_module_root" action="action_my_module_records" sequence="10"/>
</odoo>
Step 7: Install the Module in Odoo
To make your module available in the web interface:
addons_path in your odoo.conf:
addons_path = /opt/odoo/odoo/addons,/path/to/custom/addons
sudo systemctl restart odoo
Step 8: Upgrade After Making Changes
As you develop, you will update Python models and modify XML views. To apply changes without reinstalling the module, restart Odoo with the -u flag:
./odoo-bin -c odoo.conf -u my_module -d mydb
This command reloads Python code, updates the database schema, and refreshes XML view definitions in one pass.
Scaffolding a simple module is straightforward, but production ERP applications often require complex business logic, third-party API synchronizations, automated accounting flows, and rigorous testing across versions. Our team of certified developers can architect, build, and support enterprise-grade modules tailored precisely to your workflows. Learn more about our Odoo development services.
What is the difference between an Odoo module and an app?
In Odoo, every app is a module, but not every module is an "app". A standalone app provides major business capabilities (such as CRM, Invoicing, or Inventory) and sets 'application': True in its manifest. A regular module is typically a technical plugin, bridge, or workflow extension that has 'application': False, adding features to existing apps without cluttering the main app dashboard.
Can I build a module without coding (Odoo Studio)?
Yes, Odoo Enterprise includes Odoo Studio, a low-code tool that enables users to add custom fields, customize form views, and build basic automated actions through a graphical user interface. However, for complex business rules, multi-table queries, version-controlled codebases, and custom integrations, developing a Python-based module is the recommended approach.
How do I upgrade a custom module to a new Odoo version?
Upgrading a custom module to a newer Odoo release involves auditing deprecated ORM methods, updating XML view tags (such as transitioning from <tree> to <list> in Odoo 18), updating JavaScript OWL web components, and testing data migrations. If your team is planning an upgrade and needs assistance modernizing legacy custom modules, explore our Odoo migration services.
Creating custom modules in Odoo is an effective approach to customize the ERP system to your specific business needs. Businesses may confidently begin on the road of module creation with the direction and experience of O2B Technologies, a renowned leader in the Odoo ecosystem. O2B Technologies can assist you in navigating the difficulties of Odoo Module Development, whether you want to improve certain procedures, automate operations, or add new features. You can unleash the full potential of Odoo ERP and push your business operations to new heights by teaming with specialists like O2B Technologies.