Cloud Architecture

Migrating Legacy Business Monoliths to Next.js & Go with Zero Downtime

Full-Stack Platforms Team 6 min read

A big-bang rewrite of a business-critical system usually fails: it takes longer than planned, freezes feature work, and ends in a risky cut-over. The strangler fig pattern avoids that by replacing the monolith one capability at a time while it keeps serving users. This is the approach we use when modernising ERPs and operational platforms.

Put a routing layer in front of the monolith

Introduce a reverse proxy or API gateway that receives all traffic. At first it forwards everything to the legacy application, so nothing changes for users. This layer is what lets you move individual routes to new services later, and move them back instantly if something goes wrong.

location /api/invoices/ {
    proxy_pass http://new_invoice_service;   # migrated
}
location / {
    proxy_pass http://legacy_monolith;       # everything else
}

Pick slices by value and isolation

Start with a capability that has clear boundaries and real business value, such as reporting, customer-facing portals or a single module like invoicing. Avoid the most tangled core first. Each slice should be shippable on its own and reversible.

  • Read-heavy modules (dashboards, reports) are the safest first candidates.
  • Customer-facing screens benefit most from a Next.js front end with server rendering.
  • High-throughput back-end workloads suit Go services with explicit concurrency and low memory use.

Deal with shared data carefully

The hardest part is data. During migration the legacy database is still the source of truth for most tables. A new service can read from it through a narrow, well-defined interface, or the monolith can publish change events that the new service consumes. Avoid two systems writing to the same table without a clear owner.

When a slice is ready, move ownership of its tables to the new service, keep the legacy side read-only for a period, and only then remove the old code path.

Release safely

  • Shadow traffic: send a copy of real requests to the new service and compare responses before switching.
  • Feature flags or weighted routing to move a small percentage of users first.
  • Automated rollback by pointing the route back to the monolith.
  • Monitoring on error rate and latency per route, with agreed thresholds before each increase.

Finish by deleting code

A migration is only complete when the old code is gone. Track which routes and tables remain in the monolith, retire them deliberately, and decommission the legacy application once nothing depends on it. Without that last step you end up running two systems indefinitely.

Start a conversation

Tell us what you need to build.

Share the problem, your current process and the outcome you need. We will help you decide on a practical next step.