Odoo.sh Setup and Deployment: Git Workflows, Branches, and Modules That Actually Ship
Getting Odoo live isn't just installing software — on Odoo.sh, it's a Git repository with opinions. Odoo.sh maps your branches directly to environments and rebuilds the instance from source on every push, which is powerful once you understand it and a source of confusing, silent failures if you don't. Most teams hit the same handful of problems the first time they deploy custom code through it, almost always for the same underlying reason: treating it like a plain code push instead of a full environment rebuild.
This article walks through what Odoo.sh setup actually involves, why deploying custom modules through Git trips people up, and the branch and module discipline that keeps deployments boring — which, for a production system, is exactly what you want.
What Odoo.sh Actually Does
Odoo.sh is Odoo's own hosting and deployment platform, and it's built around a single idea: your Git repository is the source of truth for what runs in each environment. There's no separate deploy step where you upload a build artifact — you push to a branch, and Odoo.sh rebuilds and redeploys that environment directly from what's in the repository.
Any branch gets a disposable Development environment for testing in isolation. A designated Staging branch mirrors production data, so changes can be rehearsed against something close to the real thing. And exactly one branch — Production — is the live database. Understanding that mapping is the entire foundation of working with Odoo.sh; almost every deployment problem traces back to a branch being used for something other than its intended stage.
Initial Configuration: More Than Connecting a Repository
Setting up a new Odoo.sh project involves more than pointing it at a Git repository. Custom modules need to live in a recognized addons path that Odoo.sh will scan on build. Any external Python packages a custom module depends on need to be declared in a requirements.txt at the repository root — Odoo.sh installs from that file on every build, it doesn't inherit whatever happens to be installed in a developer's local environment.
That last point causes more first-deployment failures than anything else on this list. A module runs perfectly on a developer's machine, because their local Python environment already has the package installed globally. It fails the moment it hits Odoo.sh, because the build environment only has what requirements.txt tells it to install.
The Real Challenge: Deploying Custom Code Through Git
On a recent Odoo.sh implementation, the pattern that caused the most rework wasn't one dramatic failure — it was a handful of small, repeatable mistakes that each looked minor in isolation but compounded quickly:
Each of these produces the same experience: the build fails or the update runs cleanly but the module doesn't behave correctly, and the cause isn't obvious from inside Odoo itself — it's in the build log, which many teams don't check until something is already broken in front of a user.
A failure at any step stops the deploy there — the build log shows exactly which one, and the previous working version stays live until it's fixed.
The build log is the actual source of truth for a failed deployment. It shows exactly which step failed — dependency installation, module install, or a data migration — and the specific error, rather than the generic "something went wrong" a user sees in the app itself.
Managing Branches and Modules the Way Odoo.sh Expects
There's more than one way to structure a Git workflow for Odoo.sh, but they aren't equally good ideas. Pushing feature work directly to the production branch is the fastest way to deploy — and the fastest way to turn an untested change into a live, unrehearsed migration. It's the option we'd actively recommend against, even for small fixes.
The approach that actually holds up mirrors Odoo.sh's own environment model instead of fighting it:
- Build on a feature branch first. Every change gets its own disposable Development build, so a broken module never touches a shared environment.
- Merge to Staging before Production, always. Staging mirrors production data, which is the only place that reliably surfaces migration issues before they hit real users.
- Declare every dependency explicitly. Manifest dependencies and
requirements.txtentries should reflect what a module actually needs, not what happens to already be present in whatever environment it was last tested in. - Write a migration script for structural field changes. Renaming, retyping, or removing a field on a model with existing data needs an explicit migration step — Odoo won't infer the right conversion on its own.
- Read the build log after every push, not just the pass/fail status. A build that "succeeds" can still install with warnings worth catching before Staging becomes Production.
Of the approaches available, Staging-before-Production isn't a close call. Odoo.sh already gives you a data-realistic rehearsal environment for free — the only failure mode is not using it, and pushing straight to Production because a change "feels small."
A Deployment Checklist Before You Trust a Push
For any Odoo.sh project, this is the order that avoids a broken production deploy:
- Confirm every custom module's manifest lists its true dependencies — not just what happens to already be installed.
- Add every external Python package to
requirements.txtat the repository root. - Test on a Development branch before merging anywhere else.
- Rehearse the merge on Staging against production-like data before touching the Production branch.
- Write and test a migration script for any structural field or model change before it reaches Staging.
- Read the build log on every push — not just whether the build passed, but what it warned about.
Final Thoughts
None of the failure modes here are exotic — a missing dependency, an untested merge, a field change with no migration path. What makes Odoo.sh unforgiving of them is that it rebuilds the entire environment from your repository on every push, so a small gap in discipline shows up immediately, in production, instead of staying invisible the way it might on a server you patch by hand.
Respect the branch-to-environment mapping Odoo.sh already gives you, declare dependencies explicitly, and rehearse every change on Staging first — and deployment becomes routine. Skip that discipline, and you'll be debugging a build log in front of a broken production instance instead of before one.
Deploying custom code to Odoo.sh and want it to actually stick?
Our Odoo implementation team can set up your branch strategy, module dependencies, and migration scripts correctly from the start — so your builds fail on a feature branch, not in front of your users.
Talk to Our Odoo Team