The Load Time Problem
Your D2C brand spends thousands on Google Ads to drive traffic. A customer clicks your link. The page turns white. They wait. 1 second. 2 seconds. 3 seconds.
They bounce.
The Culprit: Your Odoo website is loading 45 separate JavaScript files and 30 CSS sheets individually. The browser has to open 75 different connections just to render the homepage.
The Solution: Odoo's built-in Assets Bundle system. It crushes those 75 files into 1 JavaScript file and 1 CSS file. It compresses them (minification) to remove whitespace and comments.
Result: The browser downloads 2 small files. The site loads instantly. Your conversion rate goes up.
We've implemented 150+ Odoo systems. We consistently see "Developer Mode" left on in production, causing 5-second load times. Turning on the asset bundle engine is the single fastest way to improve your PageSpeed score.
How Odoo Handles Assets (The Bundle)
Odoo uses a proprietary asset engine (inherited from ir.attachment and ir.asset). It doesn't use Webpack or Gulp; it uses its own Python-based logic.
The Workflow
1. Registration: Modules declare their JS/CSS files in __manifest__.py
2. Aggregation: When a page loads, Odoo checks if a "Bundle" exists (e.g., web.assets_frontend)
3. Minification: CSS (Uses Sass to compile .scss, removes whitespace/comments), JS (Concatenates files, removes whitespace)
4. Caching: Result saved as file attachment with unique hash (e.g., web.assets_frontend.min.js?v=123ab), browser caches aggressively
Configuration: The __manifest__.py
In Odoo 15+, asset registration moved strictly to the __manifest__.py file (replacing the old XML <template id="assets_backend"> method).
# __manifest__.py
{
'name': 'My D2C Theme',
'version': '1.0',
'depends': ['website', 'sale'],
'assets': {
# 1. Frontend Bundle (The Website)
'web.assets_frontend': [
# SCSS Variables first (so they override Bootstrap)
'my_theme/static/src/scss/primary_variables.scss',
# Main SCSS
'my_theme/static/src/scss/header.scss',
'my_theme/static/src/scss/product_page.scss',
# JavaScript
'my_theme/static/src/js/cart_animation.js',
'my_theme/static/src/js/variant_selector.js',
],
# 2. Backend Bundle (The ERP Interface)
'web.assets_backend': [
'my_theme/static/src/js/custom_widget.js',
'my_theme/static/src/scss/backend_overrides.scss',
],
# 3. Report Bundle (PDFs)
'web.report_assets_common': [
'my_theme/static/src/scss/invoice_layout.scss',
],
},
}
Best Practice:
Always separate your SCSS variables (colors, fonts) from the layout logic. Load variables before Odoo's bootstrap imports if possible (requires advanced inheritance) or use the _variables.scss pattern provided by Odoo's theme engine.
Activating Minification in Production
Minification is OFF by default when:
You are in Developer Mode (URL contains debug=1 or debug=assets)
You have explicitly disabled it in the configuration
To Ensure Speed in Production
1. Disable Debug Mode:
Ensure your users (and public visitors) are accessing https://yourwebsite.com, not https://yourwebsite.com?debug=assets.
2. Check odoo.conf:
Look for the dev_mode flag. It should be empty or strictly managed.
# odoo.conf
# Ensure this is NOT set to 'all' or 'assets' in prod
dev_mode =
3. Regenerate Bundles:
If you deploy new code and the site looks "broken" (CSS missing), the bundle might be stuck.
Go to Settings → Technical → Automation → System Parameters
Search for web.assets_filename parameters and delete them (or use "Regenerate Assets" button)
Troubleshooting "Asset Bundle Errors"
Every Odoo developer has seen this. You load the page, and a modal pops up: "Could not compile style sheet."
Common Causes
You missed a semicolon ; in your CSS.
Fix: Check the Odoo logs (/var/log/odoo/odoo-server.log). The Sass compiler usually prints the exact line number of the error.
You tried to use $o-brand-primary but didn't import the Bootstrap definitions file first.
Fix: Ensure your file is loaded after common.scss in the manifest bundle order.
You imported an external font via http:// on an https:// site.
Fix: Odoo's minifier often blocks insecure content.
Advanced: Using defer and Lazy Loading
For heavy JavaScript libraries (like a 3D product viewer or a Chat widget), don't put them in the main web.assets_frontend. That blocks the initial page paint.
Method 1: Defer via XML
If you inject a script in the header:
<script type="text/javascript"
src="/my_module/static/lib/three.min.js"
defer="defer"/>
Method 2: Dynamic Import (OWL/ES6)
Load the library only when the component mounts.
/** @odoo-module */
import { loadScript } from "@web/core/assets";
export class Product3DViewer extends Component {
setup() {
onWillStart(async () => {
// Only downloads the 1MB file when this specific widget is needed
await loadScript("/my_module/static/lib/three.min.js");
});
}
}
Your Action Items
Audit Your Manifests
❏ Open your custom modules
❏ Are you still using the old XML <template> method for assets? Migrate to __manifest__.py for better performance and Odoo 16/17 compatibility
Check Production Mode
❏ Go to your live website in an Incognito window
❏ Right-click → Inspect → Network Tab
❏ Reload. Do you see web.assets_frontend.min.js?
Yes: Good. No (I see cart.js, header.js, etc.): You are running in assets debug mode. Fix your Nginx or Odoo config immediately
Analyze Size
❏ Is your web.assets_frontend.js larger than 2MB?
❏ If yes, you are loading too many unused libraries globally. Use dynamic imports to split the code
Free Frontend Performance Review
Is your PageSpeed Insights score red? We'll analyze your asset bundles for bloat, identify blocking JavaScript files, fix broken SCSS inheritance chains, implement lazy loading for heavy third-party scripts. Speed is a feature. Don't let a slow site kill your sales.
