Legacy & Modernization
How to Rescue a Legacy PHP Project Without a Full Rewrite
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
Migrating from PHP 5.6/7.x to PHP 8.3: A Practical Roadmap
A step-by-step PHP 8.3 migration roadmap with realistic timelines, automated tooling (Rector, PHPStan), and the risks nobody warns you about.
Scaling a Laravel Application: From 100 to 100k Users
Concrete techniques for scaling Laravel — caching, queues, database tuning, and horizontal scaling — through every order of magnitude of growth.