Skip to content

Odoo 16 to 17 Breaking Changes: Detailed Migration Guide

DeployMonkey Team · March 24, 2026 9 min read

Overview

The Odoo 16 to 17 migration is one of the most technically demanding upgrades in Odoo's history, primarily due to the removal of the attrs attribute from XML views. This guide covers every breaking change with examples and migration patterns.

attrs Removal — Complete Guide

The attrs attribute was the standard way to define conditional visibility, read-only behavior, and required fields in Odoo views for over a decade. In v17, it was replaced with direct attributes using Python-like expressions.

Basic Patterns

# invisible:
# v16: attrs="{'invisible': [('state', '=', 'done')]}"
# v17: invisible="state == 'done'"

# readonly:
# v16: attrs="{'readonly': [('state', '!=', 'draft')]}"
# v17: readonly="state != 'draft'"

# required:
# v16: attrs="{'required': [('type', '=', 'product')]}"
# v17: required="type == 'product'"

Complex Domain Patterns

# AND conditions:
# v16: attrs="{'invisible': [('state','=','done'),('type','=','service')]}"
# v17: invisible="state == 'done' and type == 'service'"

# OR conditions:
# v16: attrs="{'invisible': ['|',('state','=','done'),('state','=','cancel')]}"
# v17: invisible="state == 'done' or state == 'cancel'"

# NOT conditions:
# v16: attrs="{'invisible': [('active','=',False)]}"
# v17: invisible="not active"

# 'in' operator:
# v16: attrs="{'invisible': [('state','in',['done','cancel'])]}"
# v17: invisible="state in ('done', 'cancel')"

# Combined attrs:
# v16: attrs="{'invisible': [('state','=','done')], 'readonly': [('state','!=','draft')]}"
# v17: invisible="state == 'done'" readonly="state != 'draft'"

Notebook Pages and Groups

# Notebook pages:
# v16: <page string="Details" attrs="{'invisible': [('state','=','draft')]}">
# v17: <page string="Details" invisible="state == 'draft'">

# Groups:
# v16: <group attrs="{'invisible': [('has_partner','=',False)]}">
# v17: <group invisible="not has_partner">

OWL 2.x Migration

Custom JavaScript components built on the legacy widget system or OWL 1.x need migration to OWL 2.x patterns:

  • Template syntax changes (t-on-click vs onClick)
  • Component lifecycle method updates
  • Service injection patterns changed
  • Registry-based component registration

View Type Considerations

While the tree-to-list rename happened in v18, v17 introduced preparatory changes to view type handling. Custom view types and JavaScript view extensions should be reviewed.

Migration Strategy

  1. Run a search for attrs= across all custom module XML files
  2. Convert each occurrence using the patterns above
  3. Test every form view with various record states
  4. Review OWL component compatibility
  5. Run the full test suite

Common Pitfalls

  • Forgetting to convert attrs on <button> elements
  • Missing attrs on <page> and <group> elements
  • Complex nested OR/AND domain conversions
  • attrs in <tree> views (column-level visibility)
  • Inherited views that override attrs via xpath

DeployMonkey Advantage

DeployMonkey's AI agent understands the attrs-to-expression migration pattern and can validate your custom modules for v17 compatibility. Deploy on Odoo 17+ with confidence that your views are correctly migrated.