Legacy & Modernization

How to Rescue a Legacy PHP Project Without a Full Rewrite

·10 min read·By Abimael Espinoza

Every legacy PHP rescue I've taken on starts with the same temptation from leadership: 'just rewrite it'. Almost every full rewrite I've seen ends in tears. Here's the incremental approach that actually ships.

Why full rewrites fail

  • The business doesn't stop. While you rewrite, the old system needs maintenance — you pay twice.
  • The original requirements were never written down. You'll re-discover them via production bugs.
  • Edge cases that took years to handle get re-broken.
  • By the time you ship, the market has moved.

The strangler fig pattern, applied to PHP

Named after the strangler fig vine that grows around a host tree until the original tree disappears, this pattern lets you replace a system one piece at a time while it stays in production.

The 5-step rescue playbook

1. Establish a safety net

  • Add observability first: error tracking (Sentry), APM (NewRelic, DataDog), structured logs.
  • Get tests on the top 5 revenue-critical user flows.
  • Set up CI even if it only runs linting at first.
  • Document the deployment process so anyone on the team can ship.

2. Carve seams

Identify modules that can be isolated behind interfaces — payments, notifications, search, reporting. These become the first candidates for replacement. The goal isn't to rewrite them yet, just to make them swappable.

3. Stand up a modern PHP application alongside

Spin up a modern PHP 8.3 / Laravel 11 (or Symfony 7) application. Route specific endpoints to it via a reverse proxy (nginx, traefik) or feature flag. Both apps share the database initially — that's fine, it's a transition state.

location /api/v2/ {
  proxy_pass http://new-app;
}
location / {
  proxy_pass http://legacy-app;
}

4. Migrate one capability at a time

  • Pick the highest-pain, lowest-risk module first (often a reporting page or admin area).
  • Implement it in the new app, behind a feature flag.
  • Cut over a small percentage of users, then 100%.
  • Delete the old code only after the new one has run cleanly for 2–4 weeks.

5. Untangle the database last

Database refactors are the highest-risk part. Use views, materialized tables, or CDC tools (Debezium) to let new and old code coexist. Eventually each table is owned by one app, and the schema can be cleaned up.

What to avoid

  • Don't rewrite UI and backend simultaneously — too many moving parts.
  • Don't skip writing tests for the legacy code you're replacing — you need a behavior contract.
  • Don't let the old codebase become 'someone else's problem' — keep the same team responsible.
  • Don't let the rescue project run more than 6 months without visible business value.

Realistic outcomes

A typical mid-sized legacy PHP rescue takes 6–18 months of part-time work to migrate ~80% of code, while the system stays live and usable. The remaining 20% often stays for years — that's fine, as long as it's well-isolated.


Need a hand?

Hiring or modernizing PHP? Let's talk.

16+ years building, scaling, and rescuing PHP applications. Direct contact, no marketplace, US time zones from LATAM.

Related reading