In modern ERP systems, performance is not optional — it directly impacts productivity and user adoption. Odoo 19 continues to improve performance through smarter data handling and frontend optimization. One of the key techniques behind this is Lazy Loading.
Lazy loading is a design pattern where data, objects, or assets are loaded only when they are actually needed, rather than at initial load time.
In Odoo 19, lazy loading exists at multiple levels:
What is Lazy Loading?
Lazy loading is a performance optimization technique in which data is loaded only when it is actually needed, rather than loading everything up front. Instead of fetching all related records, assets, or components at the initial page load, Odoo retrieves them progressively as the user interacts with the system.
In Odoo 19, this means that the framework avoids unnecessary database queries and frontend rendering during the first load of a view. Data is fetched step by step, based on user actions such as opening a form, switching tabs, scrolling through records, or triggering a specific feature.
This approach significantly improves initial page load speed, reduces server load by preventing unnecessary computations, and provides a smoother overall user experience. By delaying non-critical operations, Odoo ensures that users can start working immediately without waiting for heavy background processes to complete.
In Odoo 19, lazy loading is implemented at multiple levels:
- ORM (backend data layer)
- Form and list views
- One2many relationships
- OWL frontend components
- Website rendering
Lazy Loading in the Odoo ORM
The Odoo ORM is designed with built-in lazy loading and prefetching mechanisms.
When you browse records, Odoo does not immediately load relational fields. Instead, it waits until the field is accessed.
For example:
orders = self.env['sale.order'].browse([1, 2, 3])
At this point, related fields like partner_id are not yet loaded. They are fetched only when accessed:
partner_names = orders.mapped('partner_id.name')When this happens, Odoo loads all required partner records in batch using its prefetch system. This prevents the N+1 query problem and improves database efficiency.
This behavior is automatic and is one of the reasons Odoo performs well even with large datasets.
Computed Fields and Lazy Evaluation
Computed fields can behave lazily depending on their configuration.
If a field is defined with store=False, it is computed only when it is read. If the field is not included in a view or accessed in Python code, it is not computed.
Example:
heavy_field = fields.Char(
compute="_compute_heavy_field",
store=False
)
However, if this field is added to a list view that displays many records, it will be computed for those records. Therefore, developers must carefully decide when to use:
- store=True for frequently used values
- store=False for dynamic or rarely accessed values
Choosing correctly is important for data model optimization.
Lazy Loading in List Views
In Odoo 19, the list view (formerly called tree view) uses virtual scrolling and batched loading.
If a model contains thousands of records, Odoo does not load all of them at once. Instead, it loads records in batches as the user scrolls.
You can also control the batch size:
<list limit="40">
<field name="product_id"/>
<field name="price_unit"/>
</list>
The limit attribute defines how many records are fetched per batch. This helps reduce memory usage and improves rendering performance.
One2many Fields and Progressive Loading
One2many fields can significantly impact form performance if they contain many records. Odoo 19 handles this efficiently by loading related records progressively.
If a record contains hundreds or thousands of one2many lines, they are not all fetched at once. Instead, Odoo loads them incrementally using virtual scrolling inside the list view.
To optimize performance:
- Avoid unnecessary one2many relationships
- Archive old records instead of keeping everything active
- Use limits where appropriate
Notebook Tabs and Delayed Rendering
Form views in Odoo 19 support notebook tabs that delay loading heavy content until the user clicks the tab.
Example:
<notebook>
<page string="Order Lines">
<field name="order_line"/>
</page>
</notebook>
The order_line field is loaded only when the user opens that tab. This improves the initial form load time and reduces unnecessary processing.
Lazy Loading in OWL Components
Odoo 19 uses OWL as its frontend framework. Developers can implement lazy data loading inside custom components by fetching records only when required.
Example:
/** @odoo-module **/
import { Component, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
export class LazyComponent extends Component {
setup() {
this.orm = useService("orm");
this.state = useState({
records: [],
offset: 0,
limit: 20,
});
}
async loadMore() {
const result = await this.orm.searchRead(
"res.partner",
[],
["name", "email"],
{
offset: this.state.offset,
limit: this.state.limit,
}
);
this.state.records.push(...result);
this.state.offset += this.state.limit;
}
}
This pattern ensures that only a small dataset is loaded initially, and more data is fetched only when needed.
Website Lazy Loading
Odoo 19 also improves performance on the website side. Images and heavy assets can be loaded only when they enter the viewport.
Example:
<img t-att-src="image_url" loading="lazy"/>
This reduces initial page load time, especially for eCommerce websites with many product images.
Lazy loading in Odoo 19 is a core performance strategy implemented across the ORM, list views, relational fields, OWL components, and website engine.
By loading data only when necessary, Odoo reduces server load, improves responsiveness, and ensures better scalability. For developers, understanding how lazy loading works is essential to building high-performance and scalable Odoo applications.
When combined with good data model design and optimized queries, lazy loading helps keep Odoo fast—even as the database grows.
To read more about What are ORM Methods in Odoo 18, refer to our blog What are ORM Methods in Odoo 18.