Guide
Migrate a Monolith to Next.js and PostgreSQL
How Agentic Academy Labs strangler-migrates monoliths to Next.js, Bun, and PostgreSQL: week 1 inventory, data cutover, Flutter clients, and the risks that stall rewrites.
Published 2026-08-08 · Updated 2026-08-14
Big-bang rewrites are how products freeze. At Agentic Academy Labs we migrate monoliths (PHP, Rails, older Node) to Next.js and PostgreSQL with a strangler pattern: new UI on the App Router, Bun or Route Handlers for new APIs, old server still serving what has not moved, then data cutover with replication and checks. Flutter apps keep a stable HTTP contract while hosts change. This is the same discipline as our cloud migration checklist, applied to the application itself. Work is run from Sikar with the client's operators on the old box.
Strangler steps we follow
- Inventory screens, APIs, jobs, uploads, and who owns each table. Interns are good at this pass.
- Stand up Next.js plus PostgreSQL plus CI. Local Postgres first, hosted project second.
- Move one high-value journey (login, pay, or the screen that generates support tickets).
- Replicate or dual-write critical tables. Validate with checksums, not hope.
- Point DNS and the Flutter base URL with a flag. Keep rollback for a named window.
- Retire legacy routes only after smoke tests and a week of error budgets.
What week 1 contains
- A route map: URL, owner, traffic, and 'move / wrap / leave.'
- A restore of the current backup into a scratch Postgres. If restore fails, stop.
- Auth decision: session cookies on Next.js vs tokens the Flutter app already uses.
- SEO URL list if the monolith is public. 301s are a deliverable, not a follow-up.
- A written freeze policy: which features still land on the old stack during the strangler.
Data cutover without folklore
PostgreSQL is our default because transactional apps, reporting, and later pgvector for AI features share one operational skill. We do not rename every column for taste. We do add tenant_id and created_at where the monolith was sloppy. Dual-write is for tables that cannot freeze. Batch copy is for archives. Always compare row counts and a few business checksums (open orders, wallet sums) before calling it done. Data engineering joins when the monolith's 'reports' are actually a second system.
Risks and mitigations
| Risk | How it shows up | Mitigation |
|---|---|---|
| Feature freeze forever | Old app still getting all tickets | Time-boxed strangler phases |
| Data drift | Two totals in finance | Replication plus automated checks |
| SEO / URL breakage | Traffic cliff after launch | 301 map before cutover |
| Mobile breakage | Flutter still on old host or old JSON | Contract tests and a config flag |
| Cost spike | Two stacks live for months with no sunset date | Sunset checklist in the same board as features |
| Rewrite as AI project | Someone wants RAG before login works | Auth and data first; AI is a later slice |
Where AI fits (later)
Once the new app has Postgres and a clean API, adding RAG is the architecture in Next.js AI app architecture. Doing RAG inside the monolith's undocumented jobs is how citations rot. We have paused AI scope mid-migration when inventory showed three sources of customer truth. That pause saved the kind of corpus mess that otherwise lands in week 4 of an assistant project.
Failure modes from our migrations
- Rewriting the admin first because it is ugly. Users live in the customer journey; strangler that first.
- New Next.js app talking to the old MySQL with an ORM 'for now.' You just added a fourth runtime.
- No job inventory. Nightly invoices kept running on the old box against stale rows.
- Intern-built pages without the design system. UI/UX belongs in the landing zone, not as a polish sprint after cutover.
A focused product can move in months. A domain with years of reports takes longer. Discovery produces a phased plan; we do not quote a single weekend. Pair the work with web and mobile development and cloud migration when hosting moves at the same time. Agentic Academy Labs will schedule a call if you bring the route map, even a messy one.
Frequently asked questions
- Should we rewrite everything at once?
- Usually no. Prefer a strangler so users keep working while you move journeys. Big-bang is for stacks that are already frozen and small.
- Why PostgreSQL?
- Strong default for transactional apps, reporting, and optional pgvector later. One operational skill for the team in Sikar and for the client.
- How long does this take?
- From months for a focused product to longer for large domains. Discovery after inventory is what makes the phased plan honest.
- What about the Flutter app?
- Keep a versioned HTTP contract. Change the host behind a flag. Do not require an emergency store release as your only rollback.
- Can we add an AI chatbot during the migration?
- Only after there is one source of truth for the docs or data the bot will cite. Otherwise you migrate chaos into Slack.