Modernization

Modernizing a legacy PHP application without a full rewrite

An incremental approach that keeps the business running while the code improves.

Cover illustration for Modernizing a legacy PHP application without a full rewrite
Cover illustration for Modernizing a legacy PHP application without a full rewrite

A lot of businesses still run on PHP applications that are ten years old or more. They work. They make money. And every change takes longer than it should, because nobody quite trusts the code any more.

The obvious answer seems to be “let’s rewrite it”. We understand the appeal, but we rarely recommend it for an important system. Rewrites take longer than planned, the old system keeps changing while you build the new one, and the business waits a long time to see any benefit. Modernizing the application step by step usually gets you further, sooner, with far less risk. This is how we go about it.

Is it time to modernize?

Some signs that it is:

  • Small changes take days, because nobody is sure what else they will break
  • Releases are slow, manual or scary
  • You run a PHP version that no longer gets security fixes
  • One or two people know how the app really works
  • New developers take weeks to feel safe in the code

The last two are about people, not code, and they are just as risky. If the person who understands the app leaves, the app is in trouble.

PHP also makes the age of your code a security issue. When two serious PHP bugs were announced in October 2026, PHP 8.1 and older got no official update. We explain it in our guide to the PHP2Shell bugs. An old version means you can’t simply update when something like this happens.

Rewrite or modernize?

A full rewrite is sometimes the right call. Here is how we look at it:

Modernize step by step Rewrite
Best when The app does its job, but the code is old and hard to change The technology is a dead end, or the business has changed so much that the design no longer fits
Risk Low. Each change is small and can be rolled back High. Nothing works for the business until the new system is finished
Time to first benefit Weeks Often a year or more
New features Keep shipping the whole time Often paused, or built twice

If your main complaint is “the code is old and messy”, modernizing is almost always the better route.

Build a safety net first

Before we change anything big, we make it safe to change things at all:

  • Get the code into version control if it isn’t already, and automate deployments
  • Add error logging and monitoring so problems are visible
  • Write tests around the flows that matter most, even if they start as rough end-to-end checks
  • Make sure backups exist, and that restoring one actually works
  • Add a static analysis tool such as PHPStan, which finds whole classes of bugs without running the code

None of this is exciting, but it lowers the risk of everything that follows. If you have just inherited the code from another team, start with our application handover checklist.

Upgrade PHP one step at a time

An outdated PHP version is a security risk and a performance drag, and it locks you out of modern libraries. Upgrading PHP, the framework and the key dependencies is often the single most valuable thing you can do.

Here is when security support ended for each version:

201420162018202020222024202620282030
PHP 5.6Ended 2018
PHP 7.0Ended 2019
PHP 7.1Ended 2019
PHP 7.2Ended 2020
PHP 7.3Ended 2021
PHP 7.4Ended 2022
PHP 8.0Ended 2023
PHP 8.1Ended 2025
PHP 8.2Ends 31 Dec 2026
PHP 8.3Ends 31 Dec 2027
PHP 8.4Ends 31 Dec 2028
PHP 8.5Ends 31 Dec 2029
Today
Security support for each PHP version, from release to the end of security fixes. Grey bars have ended, the orange bar ends this year, and green bars are still supported. PHP 8.1 and older got no official update for the October 2026 PHP bugs, only source patches for 7.4, 8.0 and 8.1.

How we approach the upgrade:

  • Move one version at a time. Get the tests passing on each version before you go to the next. A break then has a small, known cause.
  • Let tools do the mechanical work. Rector can rewrite a lot of old syntax automatically. The PHPCompatibility rules for PHP_CodeSniffer list what will break on a given version.
  • Check your dependencies early. composer why-not php 8.3 shows which packages hold you back, and composer audit lists known vulnerabilities in what you use. Old libraries that nobody maintains are often the hardest part.
  • Fix deprecation notices as you go. They are PHP telling you what will stop working next.
  • Test on the new version before you deploy it. A container makes it easy to run the same code on several PHP versions side by side.

Fix the risky things early

While you are in the code, deal with the problems that put you at risk now:

  • Passwords and API keys written into the code. Move them to environment settings.
  • Database queries built by joining strings. Switch to prepared statements.
  • Passwords stored with an old hash such as MD5. Move to PHP’s built-in password_hash().
  • Input that nobody checks before it reaches the database or the screen.

These are small changes with a big effect, and the safety net from the first step makes them safe to do.

Add structure gradually

Older PHP apps often mix database queries, business rules and HTML in the same file. You don’t have to untangle it all at once.

We usually bring in a modern framework like Symfony or Laravel alongside the existing code and route new features through it. The web server sends some addresses to the new app and everything else to the old one, so users never notice the split. Composer takes over dependency management. Business logic moves out of templates and into small services that can be tested. Duplicate code gets merged as we touch each area.

Every one of those changes is small enough to release on its own, and the app keeps running the whole time.

Replace pieces, not the whole thing

Sometimes one part really does need rebuilding: a checkout nobody dares touch, a reporting module that takes minutes to load, an admin panel from another era. When that happens, we replace just that piece. We put a clear boundary around it, build the new version behind that boundary, and switch traffic over once it’s ready.

Over time more of the system moves to the new structure and the old code shrinks. Developers call this the “strangler” pattern, because the new system slowly grows around the old one until the old one can be switched off.

Keep shipping

The biggest benefit is that the business never has to pause. New features keep going out, often faster than before, while the codebase quietly gets better underneath. You see progress every few weeks, not at the end of a year-long project that might slip.

How to tell it’s working:

  • Releases get more frequent and less stressful
  • Fewer bugs come back after a fix
  • The tests cover more of the flows that make money
  • The PHP version moves up, and the list of outdated packages gets shorter
  • New developers become productive faster

A full rewrite is sometimes the right call. It should just be a deliberate decision made for a specific reason, and not the default reaction to old code.

Where to start

If you only do three things this month:

  1. Put the code in version control and automate the deploy.
  2. Add logging, and write a few end-to-end checks for your main flows.
  3. Find out which PHP version you really run, and work out the first upgrade step.

If you aren’t sure where your app stands, a short technical and security audit gives you an honest picture and a ranked plan before you commit to anything.

Frequently asked questions

How long does it take to modernize a legacy PHP app?

It depends on the size of the app, how much of it is tested, and how old the PHP version is. The useful part is that you don't wait for the end. The safety net and the first PHP upgrade step are small pieces of work, and each change ships on its own, so you see progress every few weeks.

Can we keep adding features while we modernize?

Yes, and that's the point. New features go through the new structure while the old code keeps running. Nothing has to pause. The only rule is that each change is small enough to release and, if needed, roll back on its own.

What if the app has no tests at all?

Start with a few rough end-to-end checks on the flows that make money, such as sign-up, checkout and the main report. They won't cover everything, but they will tell you quickly if an upgrade broke something important. Add more tests around each area as you touch it.

Should we move to Laravel or Symfony?

It's a good option for new features, because both give you routing, dependency injection and a large ecosystem. You don't have to move the whole app. Run the framework next to the old code, send new features through it, and move old parts over only when they need real changes.

Can we jump straight from PHP 5.6 to PHP 8.4?

You can try it in a test environment to see how big the job is, but we don't recommend doing it in production in one go. Moving one version at a time, with tests passing at each step, means every break has a small, known cause.

When does a full rewrite make sense?

When the technology is a dead end that can't be upgraded, when the business has changed so much that the old design no longer fits, or when the data model itself is the problem. If the main complaint is that the code is old and messy, modernizing is almost always safer and faster.

  • legacy PHP
  • PHP modernization
  • application modernization
  • refactoring

Want to talk this through?

Tell us what you're building, fixing or scaling and a senior engineer will reply with a clear next step.

Request a consultation
Let's build what's next

Have a complex technology problem? Let's talk.

Tell us what you're building, fixing or trying to scale. We'll help you understand the next step.