Introduction
Upgrading an Odoo database used to mean dump files, support tickets, and a long window of "please don't touch the system." On Odoo.sh, the entire workflow is built into the platform β fork a branch, click Test Upgrade, and the official upgrade.odoo.com service handles the heavy lifting in the background.
But automation only goes so far. If your custom modules aren't compatible with the target version, the upgrade fails. If you skip staging, you risk hours of unplanned downtime. This guide walks through the workflow that actually works in practice β the order, the gotchas, and the safety nets.
The Three-Branch Workflow
Every Odoo.sh upgrade follows the same path: Development β Staging β Production. Each branch has a specific role.
βββββββββββββββββββββββββββββββββββββββββ
β PRODUCTION (v18) β
βββββββββββββββββββ¬ββββββββββββββββββββββ
β fork
βΌ
βββββββββββββββββββββββββββββββββββββββββ
β 1. DEVELOPMENT (v19) β
β β’ Bump Odoo version in settings β
β β’ Upgrade your custom modules β
β β’ Verify on an empty DB β
βββββββββββββββββββ¬ββββββββββββββββββββββ
β drag β staging
βΌ
βββββββββββββββββββββββββββββββββββββββββ
β 2. STAGING (Test Upgrade) β
β β’ "Test Upgrade" sends a copy of β
β production to upgrade.odoo.com β
β β’ Restored as the staging DB β
β β’ You test on real data β
βββββββββββββββββββ¬ββββββββββββββββββββββ
β merge upgraded code
βΌ
βββββββββββββββββββββββββββββββββββββββββ
β 3. PRODUCTION (v19) β
β β’ Auto backup β upgrade β restore β
β β’ Auto rollback if anything fails β
βββββββββββββββββββββββββββββββββββββββββEach step blocks the next. Do not start a staging Test Upgrade until your custom modules build cleanly on the dev branch, and never push to production until the staging Test Upgrade is green.
Step 1 β Prepare a Development Branch
The first job is to make your custom code compatible with the target version. Custom modules are not upgraded by Odoo's upgrade service β that part is on you.
- In your Odoo.sh dashboard, fork your Production branch into a new Development branch (e.g.,
upgrade-v19). - Open the branch's Settings, find the Odoo version field, and change it to the target version (e.g.,
19.0). - Push code changes that bring each custom module up to the new version's API: deprecated decorators, field syntax, view elements, manifest dependencies.
- Wait for the build to go green. The branch now boots on the target Odoo version with an empty database, so startup errors in your custom code surface here first.
Tip: make your custom code work on an empty DB first. If it can't install fresh on v19, it won't survive a real upgrade either.
Step 2 β Run "Test Upgrade" on Staging
This is where the actual database migration is tested against real production data β but in isolation.
- From the Odoo.sh dashboard, drag your development branch into the Staging stage.
- Open the new staging branch and go to the Upgrade tab.
- Click Test Upgrade and select the target version.
- Odoo.sh sends the latest daily production backup to upgrade.odoo.com. The platform upgrades the schema and standard module data, then sends the upgraded dump back, which is auto-restored on your staging branch.
- Once the build comes up, check the upgrade log:
tail -n 200 ~/logs/upgrade.log- Resolve every error and warning before continuing.
- Test every critical workflow as a real user would: sales orders, invoices, accounting closes, custom reports, integrations. Treat anything weird as a blocker.
Step 3 β Promote to Production
Once staging is green and you're confident:
- Merge the upgraded code from your staging branch into Production. Make sure the version in
__manifest__.pyfiles and the branch settings match the target. - Communicate the maintenance window to users β production will be briefly unavailable.
- On the production branch's Upgrade tab, click Upgrade.
- Odoo.sh takes a backup automatically, sends the production DB to upgrade.odoo.com, and restores the upgraded result in place.
- If anything fails, the platform rolls back automatically to the pre-upgrade backup. You're not stranded.
Who Does What
The single biggest source of failed Odoo upgrades is confusion about scope. This is the line:
| You handle | Odoo.sh / upgrade.odoo.com handles |
|---|---|
| Updating your custom modules' source code | Upgrading standard module code |
| Fixing deprecated APIs and view syntax | Transforming the database schema |
| Pushing version-compatible code | Migrating standard module data |
| Setting the target version in branch settings | Producing the upgraded dump |
| Testing business workflows on staging | Restoring the dump on your branch |
| Approving the production promotion | Backing up production before the upgrade |
| Communicating downtime to users | Rolling back automatically on failure |
If your upgrade fails, look at the table. The answer is almost always in the left column.
Pitfalls That Cause Real Outages
Skipping intermediate versions. Odoo upgrades version-by-version. A 17 β 19 jump goes through 18 internally. Your custom modules must work on the final target β but you don't write intermediate code.
Continuing development during the upgrade. Every new commit on production during the upgrade window means re-testing on staging. Freeze the codebase from the moment Test Upgrade starts.
Ignoring the cascade. A version bump on one module forces upgrades on every dependent module β and surfaces dormant deprecation warnings as hard failures. We covered this exact failure mode in Why a Version Bump Breaks Your Odoo.sh Build.
Forgetting third-party modules. OCA or Apps Store modules without a target-version release will block the upgrade entirely. Audit dependencies before starting.
Skipping staging. "It worked in dev" means nothing β dev uses an empty database. Test Upgrade against real production data is the only meaningful validation.
Conclusion
Odoo.sh upgrades are best thought of as two parallel tracks: code (yours) and data (Odoo's). The platform handles data transformation, automatic backups, and rollback. You handle making your modules compatible and validating that the business still runs after.
The order matters: dev β staging β production, with a code freeze in between. Skip a step and you'll pay for it in downtime. Follow the workflow and most upgrades land cleanly β boring, even.
If you're staring at a failed upgrade.log and not sure where to start, the message you want to find is rarely about the database. It's almost always about a module that wasn't ready.
