Ask a CFO whether to go big-bang or phased and you get a budget answer. Ask an engineer and you get the right one, because this is an integration-architecture decision wearing a finance costume.
The question is not "how much disruption can we absorb." It is "how many systems of record am I willing to have at once, and for how long." Every other trade-off falls out of that.
What phasing actually costs you technically
The pitch for phased is that risk goes down because you change less at a time. That is true of user-facing risk and false of data risk.
Say you go live with Odoo Accounting and Inventory in March, and defer Sales and Purchase to September. For six months, sales orders live in the legacy system and stock lives in Odoo. Which means you now own:
- An interface pushing legacy orders into Odoo as
stock.pickingrecords, or a nightly reservation sync - A reverse interface returning available quantities so legacy quoting does not oversell
- A reconciliation process, because those two will drift
- Two places where a user can change a unit price, and a rule about which one wins
That is not a lower-risk configuration than a big-bang. It is a lower-change configuration with a distributed-systems problem bolted on for two quarters. Anyone who has maintained a temporary integration knows how the word "temporary" performs under load.
The dependency graph is the thing to look at. In Odoo, sale depends on stock for delivery and on account for invoicing; mrp depends on stock and purchase. Cut the phase boundary across one of those edges and you are hand-rolling what the framework gives you for free.
The dual-write problem, concretely
Any phase boundary that leaves inventory in one system and order intake in another is a dual-write. You will need a reconciliation job, and you should write it before go-live rather than in week three when the numbers stop matching.
Something roughly this shape, against Odoo's external API:
import xmlrpc.client, csv
from collections import defaultdict
URL, DB, USER, KEY = "https://erp.example.ca", "prod", "svc_recon", "..."
common = xmlrpc.client.ServerProxy(f"{URL}/xmlrpc/2/common")
uid = common.authenticate(DB, USER, KEY, {})
models = xmlrpc.client.ServerProxy(f"{URL}/xmlrpc/2/object")
quants = models.execute_kw(DB, uid, KEY, "stock.quant", "search_read",
[[["location_id.usage", "=", "internal"]]],
{"fields": ["product_id", "quantity", "reserved_quantity"]})
odoo_qty = defaultdict(float)
for q in quants:
odoo_qty[q["product_id"][1]] += q["quantity"] - q["reserved_quantity"]
with open("legacy_available.csv") as fh:
for row in csv.DictReader(fh):
drift = odoo_qty.get(row["sku"], 0.0) - float(row["available"])
if abs(drift) > 0.001:
print(f"{row['sku']}\tdrift={drift:+.3f}")
Twenty lines, and it runs nightly for six months. Fine. The point is that it exists at all, that someone has to read its output every morning, and that a big-bang rollout does not need it.
Note reserved_quantity in there. Half the drift you will chase during a phased rollout is reservation semantics — the legacy system's idea of "committed" and Odoo's idea of "reserved" are not the same concept, and reconciling on quantity alone will have you hunting ghosts.
What big-bang actually costs you
One weekend, and no rollback worth the name.
The rollback story is where big-bang is genuinely weaker, and I would not let anyone talk past it. Once Monday's transactions are in the new system, going back means either replaying them into the legacy database or losing them. In practice, by Monday afternoon you are committed. That is a real risk and it is not eliminated by good planning, only reduced.
What good planning does eliminate is the reason you would want to roll back. A two-day parallel run — same week's transactions through both systems, outputs reconciled line by line — is what turns cutover weekend from a leap into a rehearsal. Projects that skip it are the ones with rollback conversations.
The honest decision rule
For Canadian companies under about 250 staff, on a single ERP suite, my position is fairly firm:
Phase by site or legal entity. Do not phase by module.
Phasing by site works because each site is a complete system of record for itself — one plant goes live fully on Odoo, the other keeps its legacy stack fully, and the only interface between them is the consolidation you needed anyway. Phasing by module works only when the modules are genuinely decoupled, and inside a single ERP suite they are decoupled by design inside the system and coupled by process outside it.
There is one module-level phase boundary I do think is safe, and it is HR and payroll. Payroll's coupling to the rest of the ERP is one journal entry per run. Deferring it is cheap, and the timing argument in Canada is strong: T4 information returns are due the last day of February, so switching payroll systems in Q1 buys you a filing cycle of grief for no benefit. Take payroll live in July.
Two Canadian wrinkles that change the maths
Multi-province tax makes big-bang more attractive, not less. If you sell into five provinces, your tax determination logic has to be right in one place. Running it in two systems for two quarters, with GST/HST/PST/QST mappings maintained twice, is exactly the kind of duplicated configuration that produces a filing correction. Tax is not a good candidate for a temporary interface.
Version support pressure is real. Odoo maintains only the three most recent major versions, and Odoo 19 shipped in October 2025. A phased rollout that starts on Odoo 19 in early 2026 and finishes in mid-2027 will spend its second half on a version approaching the edge of that window, with an upgrade landing on top of a half-finished implementation. Compressing the timeline is worth something on that basis alone, and it is the argument I would actually make to a CFO. Version-window pressure belongs in the architecture conversation rather than the support contract, and an experienced Odoo implementation team will raise it during scoping instead of in year two. If nobody on your shortlist brings it up, ask why.
Where the budget argument comes back in
Panorama's 2026 ERP Report found more than a quarter of organizations exceeded their project budgets, with additional technology needs the leading cause. Temporary integrations are exactly that: additional technology, procured mid-project, justified as short-term, maintained for years. Every phase boundary is a small chance of a permanent middleware line item.
The checklist
Choose big-bang if most of these are true: single site, or multiple sites on one process model. Under 250 staff. One legacy accounting system rather than three. A slow quarter you can cut over into. Enough internal bandwidth for a two-day parallel run.
Choose phased if: multiple legal entities or genuinely different operating models per site; a site you can treat as a pilot without cross-site inventory movement; or a hard external constraint — an audit, an acquisition, a customer EDI deadline — that fixes one date and lets the rest move.
If you find yourself phasing because the project feels too big to do at once, that is not an architecture reason. That is a resourcing reason, and it is better solved by adding people to the discovery phase than by adding an integration you will still be maintaining in 2028.
Top comments (0)