Odoo Development · intermediate · 12 min read
Deployment Best Practices
Shipping Odoo modules safely: staging parity, -u vs -i, backups, zero-downtime limits, workers, logging, and rollback playbooks for on-prem and Odoo.sh.
Last reviewed 2026-07-30 · Estimated effort: 2–6 weeks typical implementation slice
Table of contents
Deploying Odoo is deploying code and database state together. New modules install with -i; changes to existing modules require -u to load XML/Python updates. Both need matching addons_path, dependencies, and often a brief maintenance window.
Staging must mirror production Odoo version, enterprise commit, custom modules, and worker config — not a developer laptop with extra apps installed.
Rollback is restore-from-backup for failed -u — not git revert alone. Document pre-deploy backup, smoke tests, and who approves prod -u.
Production surprises come from skipping staging -u, missing manifest data files, or cron storms after deploy. Discipline beats heroics on release night.
This article covers release mechanics for Odoo 16/17 on common hosting patterns — adapt details to Odoo.sh, Docker, or bare metal.
-i module_name creates tables, loads data, runs hooks on fresh install. -u module_name upgrades existing installation — replays data XML (respecting noupdate), runs migrations, updates views.
Production deploy of changed code almost always means -u affected modules. Order matters when modules depend on each other — upgrade dependency chain first.
- ▸--stop-after-init for scripted deploy without leaving shell open
- ▸Update apps list after copying new addons to path
- ▸Restart workers after Python-only changes — some hosts auto-reload
Weekly or per-sprint refresh staging DB from anonymized prod snapshot. Run same -u command planned for prod on staging first; capture log file and QA sign-off.
Promote exact Git tag or commit SHA from staging to prod — not main tip untested hours later.
Full pg_dump plus filestore backup before prod -u. Verify backup restore quarterly. Rollback = restore DB + filestore + prior code checkout — document RTO/RPO.
For failed view load, hotfix forward is sometimes faster than restore — keep decision tree in runbook.
Configure workers, memory limits, and gevent/longpolling per Odoo docs and traffic. After deploy, watch CPU and cron backlog — new job may need interval tuning.
Put reverse proxy timeouts above long report generation thresholds or move heavy reports to async cron.
Post-deploy smoke: login, open critical forms, confirm sale→delivery→invoice path, trigger integration heartbeat, check error log for Traceback.
Ship DEPLOY.md with module list, -u order, manual data steps, and comms template for users.
- ✓Automate deploy script — human typing module names causes typos.
- ✓Freeze prod changes during cutover except deploy PR.
- ✓Separate database migration window from code deploy if downtime sensitive.
- ✓Use maintenance page on reverse proxy during major -u.
- ✓Keep last-known-good Git tag labeled on every successful prod deploy.
- ✓Align cron active flags — disable risky jobs until smoke passes.
- !Deploy Python without restarting odoo service — old bytecode served.
- !Run -u on prod without staging replay same day.
- !Backup only DB, not filestore — attachments missing after rollback.
- !Install module on prod that was never on staging addons_path.
- !Multiple admins clicking Update Apps simultaneously during go-live.
- !Assuming Odoo.sh removes need for QA on custom -u.
Safe deploy is staged, backed up, logged, and smoke-tested — then communicated. Git merge alone is not deployment.
Long-running programmes need governance beyond single releases — see maintaining large Odoo projects for multi-module ownership.
Dev → CI tests → staging -u → QA → prod backup → prod -u → smoke.
Build
CI installs deps and runs tests.
Stage
Deploy to staging with prod-like data.
Approve
UAT and change board.
Promote
Production deploy with rollback ready.
- Owners named
- UAT scripts signed
- Rollback documented
- Hypercare roster ready
Frequently asked questions
Can I deploy without downtime?
Minor Python fixes with multi-worker reload may avoid full downtime. Schema-changing -u usually needs maintenance window — plan accordingly.
What goes in Git vs server-only?
All custom modules in Git. Secrets in env or ir.config_parameter — never committed. Filestore stays on server/object storage — not Git.
How do I deploy only one module change?
Pull code, restart if needed, odoo-bin -u that_module --stop-after-init on prod after staging proof. List dependent modules if manifest changed.
When should I use Odoo.sh staging branches?
Odoo.sh ties branches to builds — push to staging branch, test, merge to production branch. Same discipline: -u logs and smoke tests.
Related articles
Testing Odoo Modules
Automated testing for Odoo addons: TransactionCase, SavepointCase, test tags, mocking RPC, view loading checks, and CI patterns for Odoo 16/17.
View →Maintaining Large Odoo Projects
Governance for multi-module Odoo estates: ownership, branching, dependency maps, technical debt triage, documentation, and sustaining teams after go-live.
View →Writing Upgrade-Friendly Code
Engineering patterns that survive Odoo version upgrades: inheritance over fork, xpath stability, migration scripts, noupdate data, and avoiding private API coupling.
View →Scheduled Actions and Cron Jobs
Designing reliable Odoo cron jobs: ir.cron configuration, idempotency, batching, failure handling, and alternatives to infinite server actions.
View →Need a deploy runbook or first production release support?
We script -u promotion, backup checks, and smoke paths so go-live is rehearsed — not improvised.
