Introduction
Migrating custom Odoo modules between versions is one of the most time-consuming tasks for Odoo developers and partners. With Odoo 18 introducing significant changes to views, Python APIs, and JavaScript components, a structured approach is essential.
This guide covers every major change between Odoo 17 and 18, with practical before/after code examples and tips for automating the process.
Major Changes in Odoo 18
1. Tree Views Renamed to List Views
One of the most visible changes in Odoo 18 is the renaming of <tree> views to <list>. While <tree> still works as a deprecated alias, all new code should use <list>.
Before (Odoo 17):
<record id="view_partner_tree" model="ir.ui.view">
<field name="name">res.partner.tree</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<tree string="Partners">
<field name="name"/>
<field name="email"/>
</tree>
</field>
</record>
After (Odoo 18):
<record id="view_partner_tree" model="ir.ui.view">
<field name="name">res.partner.list</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<list string="Partners">
<field name="name"/>
<field name="email"/>
</list>
</field>
</record>
2. attrs Attribute Removed
The attrs attribute that was used for dynamic visibility, readonly, and required conditions has been completely removed. Instead, use direct attributes on the field elements.
Before (Odoo 17):
<field name="partner_id"
attrs="{'invisible': [('state', '=', 'draft')],
'required': [('state', '=', 'confirmed')]}"/>
After (Odoo 18):
<field name="partner_id"
invisible="state == 'draft'"
required="state == 'confirmed'"/>
3. name_get Replaced by _compute_display_name
The name_get method has been deprecated in favor of the computed field _compute_display_name.
Before (Odoo 17):
def name_get(self):
result = []
for rec in self:
name = f"[{rec.code}] {rec.name}"
result.append((rec.id, name))
return result
After (Odoo 18):
@api.depends('code', 'name')
def _compute_display_name(self):
for rec in self:
rec.display_name = f"[{rec.code}] {rec.name}"
4. track_visibility Replaced by tracking
The track_visibility parameter on fields has been replaced by tracking.
Before (Odoo 17):
name = fields.Char(track_visibility='onchange')
state = fields.Selection([...], track_visibility='always')
After (Odoo 18):
name = fields.Char(tracking=True)
state = fields.Selection([...], tracking=True)
5. OWL Component Changes
Odoo 18 continues the migration to OWL 2. Key changes include updated lifecycle hooks and component registration.
Before (Odoo 17):
const { Component, useState } = owl;
class MyComponent extends Component {
setup() {
this.state = useState({ value: 0 });
}
}
MyComponent.template = 'my_module.MyComponent';
After (Odoo 18):
import { Component, useState } from "@odoo/owl";
import { registry } from "@web/core/registry";
class MyComponent extends Component {
static template = 'my_module.MyComponent';
setup() {
this.state = useState({ value: 0 });
}
}
registry.category("actions").add("my_action", MyComponent);
6. Manifest Version Format
The version in __manifest__.py must be updated to reflect the target Odoo version.
Before: 'version': '17.0.1.0.0'
After: 'version': '18.0.1.0.0'
Additional Changes to Watch
- column_invisible — now uses direct
column_invisibleattribute instead of being insideattrs - Security CSV files — Group references must be fully qualified (e.g.,
base.group_usernot justgroup_user) - website.published_button template changes for website modules
- Mail thread mixins —
_track_subtyperenamed to_track_template - Report actions —
report.paperformat_idhandling updated
Automate Your Migration with MigrateFelix
Manually updating every file in your module is error-prone and time-consuming. MigrateFelix automates the repetitive migration work using 62 deterministic rules combined with AI analysis.
How it works:
- Upload your custom module as a ZIP file
- Select source version (17) and target version (18)
- MigrateFelix analyzes every file — Python, XML, JavaScript, CSV
- Download your migrated module with a detailed report
The entire process takes minutes instead of hours or days of manual work.
Migration Checklist
Use this checklist to verify your migration is complete:
- Update
__manifest__.pyversion to 18.0.x.x.x - Replace all
<tree>with<list> - Remove
attrsand use direct domain attributes - Replace
name_getwith_compute_display_name - Replace
track_visibilitywithtracking=True - Update OWL components to OWL 2 syntax
- Verify security CSV group references are fully qualified
- Test all views, reports, and workflows
- Create a migration script if database schema changed
Conclusion
Migrating from Odoo 17 to 18 requires attention to several breaking changes, but with the right tools and a systematic approach, it can be done efficiently. Whether you do it manually using this guide or automate it with MigrateFelix, the key is to test thoroughly after migration.
Have questions about your specific migration scenario? Contact us — we're happy to help.