Migrating from PHP to Node.js is one of the most common legacy modernisation projects we undertake for UK clients. Whether you're running Laravel, Symfony, or a custom PHP monolith, the decision isn't whether to migrate, it's how. A big bang rewrite rarely works. A phased, parallel run approach almost always does.
1. Rewrite vs Refactor: Why Full Rewrites Usually Fail
Before committing to a PHP to Node.js migration, the first question is: do you need a full rewrite or can you refactor in place? A full rewrite means building a new system from scratch and switching over. It sounds clean. In practice, it carries enormous risk.
Most rewrites fail because they underestimate three things: undocumented business logic, integration complexity, and user tolerance for change. Your PHP system has evolved over years. Edge cases, workarounds, and implicit rules live in code that nobody fully understands. Rebuilding from scratch means rediscovering, or losing, that logic.
The safer approach is incremental migration. You keep the old system running. You build the new Node.js system module by module. You switch traffic only when each module is proven. If something breaks, you roll back in minutes, not weeks.
2. The Parallel-Run Approach: Strangler Fig Pattern
The strangler fig pattern, coined by Martin Fowler, is the standard technique for legacy system modernisation. You introduce a facade or API gateway in front of both systems. New functionality is routed to the Node.js service. Older routes stay on PHP. Over time, you migrate routes one by one until the PHP application is fully replaced, then you retire it.
In practice, this means:
- Deploy an API gateway (nginx, Kong, or a simple Node.js reverse proxy) that routes requests based on path or header.
- Build new Node.js endpoints for the highest value or highest traffic features first.
- Point the gateway at the new endpoints when ready; PHP handles the rest.
- Run both systems against the same database (or a replicated copy) during the transition.
Your users never see a single "maintenance window." Business continues uninterrupted.
3. Database Migration Strategy
The database is usually the hardest part. PHP systems often use MySQL or PostgreSQL with schema designs that evolved organically, denormalised tables, missing indexes, implicit relationships. You have three main options.
Option A: Shared database. Both PHP and Node.js read and write the same database. Easiest to implement, but you must avoid schema changes that break either system. Best when the schema is relatively clean.
Option B: Read replica for Node.js. Node.js reads from a replica; writes still go through PHP. Use this for read heavy migrations (e.g. dashboards, search, reporting) while you rebuild write paths later.
Option C: Event sourced sync. PHP emits events on writes; Node.js consumes them and maintains its own read optimised store. More complex, but gives you a clean boundary and the ability to reshape data for the new system.
For most UK clients, we start with Option A or B. Option C is reserved for systems with high write volume or strict data isolation requirements.
4. API-First Architecture
Your new Node.js system should be API first from day one. That means clear REST or GraphQL contracts, versioned endpoints, and documentation. Even if your current PHP app serves HTML directly, the Node.js replacement should expose APIs. A React or Vue frontend can then consume those APIs, and so can future mobile apps, partners, or internal tools.
Design the API to match how the business works, not how the old PHP code was structured. Use this as an opportunity to fix naming, consolidate endpoints, and remove legacy cruft. The API becomes the source of truth for the new system.
5. Handling Undocumented Business Logic
Every legacy system has logic that isn't in the documentation. It might be in a 300 line function, a cron job, or a trigger in the database. Finding it requires a disciplined discovery phase: code review, database audits, and interviews with long tenured staff.
We typically allocate one week of technical audit before writing any new code. We trace user flows end to end, document every integration, and flag anything that looks like implicit business rules. That output becomes the specification for the Node.js rebuild. Skipping this step is the most common cause of post migration bugs.
6. Testing Strategy During Migration
Testing must run continuously. For each migrated module, we build:
- Contract tests, the new API matches the expected request/response shape.
- Integration tests, the new module works correctly with the shared database and downstream services.
- Comparison tests, for the same inputs, the new system produces the same outputs as the old one. Run both in parallel and diff results.
Comparison tests are especially valuable. You can replay production like data through both systems and catch behavioural drift before users do.
7. The 30–60 Day Stabilisation Period
Go live isn't the finish line. Plan for a 30–60 day stabilisation period where the old PHP system stays running as a fallback. Your team (or ours) is on standby. Critical bugs get fixed within hours. You monitor error rates, latency, and user feedback. Only when you're confident do you fully retire PHP.
At RG INSYS, we build this period into every legacy redevelopment engagement. It's not an add on, it's how we ensure zero downtime migrations actually stay zero downtime when something unexpected happens.
Migrating from PHP to Node.js is a significant undertaking, but it doesn't have to be a gamble. With the right approach, parallel run, shared database where appropriate, API first design, thorough discovery, and a proper stabilisation window, you can modernise your legacy system without disrupting your business.
Planning a PHP to Node.js migration?
We've delivered zero downtime legacy migrations for UK recruitment platforms, telecom enterprises, and SaaS companies. Get a free scope, timeline, and cost estimate within 48 hours.
Book a Free Consultation →