Skip to Content

Odoo Migration

Moving Odoo Between Online, Odoo.sh and Self-Hosted

Hosting migrations are mechanically simple and organisationally underestimated. The database moves in an afternoon. What actually changes is who is responsible for backups, upgrades, security and the phone call at 2am, and that part is not in the runbook.

Written by Muneeb AhmadOdoo 19 and 17 Certified, Functional Consultant

Part of our guide to Odoo Migration

Three platforms, and what Odoo means by each

The technical move is broadly the same in every direction. What differs is the constraint set at the destination, and that decides whether the move is an afternoon or a development project.

Odoo Online is the managed SaaS platform. Odoo's documentation is blunt about the boundary: "Odoo Online is incompatible with custom modules or modules from the Odoo Apps Store." Customisation happens through configuration and Studio. Most constrained, least to operate.

Odoo.sh is Odoo's own cloud platform for databases that carry code. Odoo describes it as "the official cloud platform for hosting and managing Odoo applications", offering "web shell, module dependencies, continuous integration, and SSH access". Custom modules are allowed and Odoo still runs the infrastructure.

On-premise is the term Odoo's own documentation uses, and it is broader than "a server in your building". It covers any deployment you run yourself: a packaged installer, a source install, or the official Docker base image. Odoo's administration guide says packaged installers "can be used for long-term production with additional deployment and maintenance work". That is not a product you buy, it is work you take on.

The hosting decision matrix

Every row below is sourced. Product rows come from Odoo's official 19.0 documentation, fetched 6 September 2026; where a row is our own observation rather than documented product behaviour it is labelled, and the section after the table explains how to read that.

DimensionOdoo OnlineOdoo.shOn-premise
Custom modules and Apps StoreNot compatibleSupported, deployed from GitSupported
Deployment modelNo code deploymentGit branches; a push to the production branch updates and restarts the production serverYours to build
StagingDatabase duplicates, testing mode on by default, expiring after 15 days, maximum five per databaseStaging branches are "neutralized duplicates of the production database", auto-deleted after one monthYours to build
Shell and SSHNot offeredShell tab into the container plus SSH by key; "Long-running SSH connections are not guaranteed"Full
Direct database accessDatabase manager actions onlypsql from the Shell tabFull
Backups"Databases are backed up daily as per the Odoo Cloud Hosting SLA"Seven daily, four weekly, three monthly; each includes dump, filestore, logs and sessions. Staging branches are not backed up automaticallyYours to configure and yours to test
Upgrade triggerRolling release; "an automatic upgrade to the next version will be triggered if no action is taken before the specified due date"Upgrade tab for production and staging branchesCommand line, when you choose
Version freedomMajor versions upgrade on roughly a two-year cycleThree years of support, then two more years to complete the upgrade"You can stay on the same version indefinitely, even if it is not recommended"
InfrastructureOdooOdooYou
ScalingPlan changesDatabase workers settingYou size it: Odoo's guidance is (#CPU * 2) + 1 workers, and "1 worker ~= 6 concurrent users"
Monitoring and logsAdmin activity logsLogs tab, real time, including odoo.log, install.log, update.logYours to build
Outbound emailOdoo-managedProduction sends for real; staging and development are intercepted by a mail catcherYours to configure
Operational burdenLowestSharedHighest

How to read the matrix

Three kinds of claim get mixed together in hosting comparisons, and mixing them is how people plan against something nobody promised. [Odoo product fact] is documented behaviour, quoted from Odoo's 19.0 documentation. [CODEerts experience] is what we have observed, which is evidence but not a guarantee. [Interpretation] is a conclusion drawn from the first two.

Two rows need their label made explicit. "Shell and SSH: not offered" on Odoo Online is [Interpretation]: the documentation lists what the database manager can do and shell access is not among them, but no page says "there is no SSH" in those words. "Operational burden" is [Interpretation] throughout. It is a judgement, not a specification, and it is the row most worth arguing with.

Direction decides difficulty

Odoo documents all six transfer directions, and they are not symmetrical.

Moving outward, from Online towards Odoo.sh or on-premise, is the easy direction: download a backup from the database manager and restore it at the destination, which permits everything the source permitted.

Moving inward is where projects fail. Odoo Online "is not compatible with non-standard apps", so the documented procedure for on-premise to Online is to duplicate the database, uninstall every non-standard application in the duplicate, take a dump with filestore, and raise a support ticket. Odoo validates compatibility before activation.

Coming from Odoo.sh, the documented order is to uninstall non-standard apps in staging first, then production, then raise the ticket. There is a second trap on that route: intermediary versions are not supported, so a database on 16.3 has to reach a major version before it can move.

Establish the direction first. If it is inward, inventory the custom modules before agreeing a date, because that inventory is the actual project. The same module inventory that drives an upgrade estimate drives this one.

Staging is the difference people underestimate

The staging row is where the three platforms separate most sharply in daily use, and it is rarely what decides the choice. It should be one of the things that does.

Odoo.sh staging branches are neutralized copies of production, and neutralization is specific: scheduled actions are disabled, outgoing emails are intercepted by a mail catcher instead of sent, IAP services are disabled, and payment providers and shipping connectors are placed in test mode. That is a safe rehearsal environment you get without building one.

Two limits matter before you rely on it: staging databases are not automatically backed up, and they are deleted after one month. Anything you need to keep does not live there.

On Odoo Online the equivalent is a database duplicate with testing mode on, expiring after 15 days, five at most. On-premise, neutralization is a script you run and a discipline you enforce.

What each platform actually promises about backups

This is the row people assume rather than read.

Odoo Online states that "databases are backed up daily as per the Odoo Cloud Hosting SLA". Odoo.sh publishes an explicit schedule: seven daily, four weekly and three monthly backups, each containing the database dump, the filestore, logs and sessions. On-premise, the promise is whatever you configured, and it is worth exactly as much as your last tested restore.

That last clause is [CODEerts experience], not documentation. A backup nobody has restored is a belief, and the moment you discover which it was is the worst possible moment.

Who decides when you upgrade

Odoo supports each major version for three years. What differs is who holds the trigger.

On Odoo Online you do not. The platform runs a rolling release and "an automatic upgrade to the next version will be triggered if no action is taken before the specified due date". Odoo's Upgrade Team runs a silent test upgrade of every database due for one.

On Odoo.sh you upgrade production and staging branches from the Upgrade tab, and after the three years of support you get two further years to complete the move.

On-premise, Odoo's own documentation says "you can stay on the same version indefinitely, even if it is not recommended". That is the sentence that sells self-hosting and the sentence that produces the five-year-old install nobody wants to touch. Freedom to defer is not the same as freedom from consequences.

What self-hosting actually signs you up for

Odoo's deployment documentation is a useful antidote to "we'll just run it ourselves", because it lists the work plainly.

The PostgreSQL user "must not be a superuser". dbfilter "must be set, otherwise a number of features will not work correctly". The admin_passwd must be randomly generated, and Odoo states that "it is strongly recommended to disable the Database Manager for any internet-facing system". On transport: "Odoo transmits authentication information in cleartext. This means a secure deployment of Odoo must use HTTPS", which means a reverse proxy and proxy mode. And demo data must never be installed on an internet-facing server.

None of that is exotic. All of it is now yours, permanently, including the parts that only matter on the day they fail.

Take the version with you unchanged, and know what it costs when you cannot

Restore the same version you left on, confirm the new platform behaves identically, then upgrade separately. Combining them is tempting because both need downtime, and it reliably turns a small project into a confusing one: when a report comes out wrong afterwards, the cause is either the platform or the version, and telling them apart means unpicking both.

Sometimes the combination is the requirement rather than a choice. [CODEerts experience]: we ran a migration for a Saudi enterprise group that moved Odoo 16 to 18 and Odoo.sh to on-premise at the same time, with Accounting, Invoicing and biometric attendance live throughout. Every custom module had to be brought to v18 compatibility, the data pipelines were monitored through the cutover rather than checked at the end, the biometric attendance integration was carried across and re-verified on the new platform, and performance and stability work continued after go-live. The migration completed with data integrity maintained and stability improved after cutover.

The transferable point is not that it worked. It is what it took: a combined move is not a hosting change with an upgrade attached, it is a full migration programme, and it has to be scoped and staffed as one from the start. We have no published timings or percentages for that engagement and will not invent them.

Name the owner of every row you just took on

On Odoo Online, backups happen whether or not anyone remembers. On your own server they happen because somebody configured them, and they are useful because somebody tested a restore. The same applies to patching, monitoring, capacity, and knowing who gets called when it stops.

Before the move, put a name against each row of the matrix that changed column. If the honest answer is "we assumed it was handled", the move is not ready. That gap does not show up at cutover; it shows up the first time you need a backup nobody verified.

If the operational rows are the part you would rather not own, that is the work we do as Odoo migration and upgrade.

Cut over like any other migration

The mechanics are familiar: a freeze window in which nobody writes to the old system, a restore, verification, then users.

The dump carries the records. The part people forget is the filestore, which holds attachments, uploaded documents, product images and report archives as files rather than rows. A restore without it looks successful, right up until somebody opens last year's invoice PDF and it is gone. Odoo's own inward-transfer procedure specifies a dump with filestore for exactly this reason.

These travel separately and each needs its own step: domain and DNS, the SSL certificate, outbound and inbound email, scheduled jobs outside Odoo, and every integration endpoint pointing at the old URL. Payment providers, carriers, webhooks and internal scripts all hold your address, and none will tell you they are still using the old one.

Keep the old instance running and reachable until you are certain, because that is what your rollback plan depends on, and run the validation checks afterwards rather than assuming a dump and restore is lossless. It usually is. The point of checking is the case where it was not.

FAQ

Questions, answered.

Can we move from Odoo Online to our own server?

Yes. Odoo Online provides a database dump including the filestore, and that can be restored onto Odoo.sh or your own infrastructure. Moving outward is the straightforward direction because the destination allows everything the source allowed, plus custom code.

Can we move from self-hosted back to Odoo Online?

Only if the database contains nothing Odoo Online forbids, which in practice means no custom modules. If you have custom code you can move to Odoo.sh instead, or the custom functionality has to be removed or rebuilt in Studio first.

Do we need to upgrade the version at the same time?

No, and you should not. Restore the same version on the new platform, confirm it behaves identically, then upgrade separately. Doing both at once means any problem has two possible causes and you will spend the cutover window arguing about which.

With CODEerts

Planning an upgrade?

We are certified Odoo partners. We migrate and upgrade Odoo databases, including the custom modules and integrations that decide how long it really takes.

See how we can helpBook a call