Problem
A government tourism platform running on React 16 with real users on it. The stack was old enough to be holding back both performance and hiring, and there was no window to stop shipping.
Approach
Incremental migration rather than a rewrite. Routes moved to Next.js one at a time behind the same domain, so the legacy app kept serving everything that had not moved yet. Shared components were ported first, because every route needed them.
Server-side rendering came with the move and mattered more here than it would on most products. A tourism platform lives on search traffic.
Hard decision
Rewrite versus incremental. A rewrite is faster to reason about and produces a cleaner result, and it also means running two products until the day you cut over. On a live government site with a small team, the migration path that never has a big-bang cutover wins even though it takes longer.
What I'd change
The before-and-after was never measured properly. Crash rate was, and it came down by roughly 5-6% once crash handling went in, but load time and bundle size across the migration would have made the case in one line instead of a paragraph.
Source
Client work for a government body, published here under an anonymised name. The platform is public; the code is not. I can walk through the migration in detail on a call.