Symfony 6.4 to 7.4: the upgrade to do before November 2026

Symfony 6.4 stops receiving bug fixes in November 2026. Security fixes continue for another year, until November 2027, but after that the version is done.

If you are on 6.4, this is your window. And the good news is that the upgrade is much less work than the version numbers suggest, provided you understand what Symfony is actually asking you to do.

Where the versions stand

VersionPHPBug fixes untilSecurity until
5.4 LTS7.2+ended Nov 2024Feb 2029
6.4 LTS8.1+Nov 2026Nov 2027
7.4 LTS8.2+Nov 2028Nov 2029
8.x8.4+rolling, 8 months eachn/a

Two things in that table matter more than the rest.

5.4 has an unusually long tail. Its security support runs to February 2029 because Ibexa sponsored an extension for their DXP. That is why you still meet Symfony 5.4 codebases in 2026. It is supported, but it stopped getting bug fixes two years ago, and everything below assumes you are moving off it eventually.

PHP 8.4 is the real gate on Symfony 8, not Symfony itself. Symfony 8 requires it because it uses PHP's native lazy objects and HTML5 parser rather than shipping its own. If your hosting is on PHP 8.2, your Symfony 8 date is set by your PHP upgrade, not your framework one.

The thing that makes this easy

Symfony 7.4 and Symfony 8.0 were released on the same day, at the end of November 2025. They have the same features. The only difference is that 8.0 contains no deprecated code.

Read that again, because it changes how you should plan.

Upgrading to Symfony 8 is not a feature migration. There is no new API to learn and nothing to rewrite in a new style. Symfony 8 is Symfony 7.4 with the deprecated parts deleted. So the work is entirely deprecation cleanup, and you can do all of it while still running 7.4, in production, with everything working.

The useful mental model: do not plan an upgrade to Symfony 8. Plan a deprecation cleanup on 7.4. When your deprecation count reaches zero, the major upgrade is a line in composer.json.

The path

Symfony's own recommended sequence, and it is worth following in order:

  1. Get to 6.4 if you are not there. This is the last 6.x release and it carries every deprecation notice for 7.0.
  2. Fix the deprecations reported on 6.4.
  3. Move to 7.4. If step 2 was thorough, this is mostly a Composer change.
  4. Fix the deprecations reported on 7.4. These are the 8.0 removals.
  5. Move to 8.x when you are ready and on PHP 8.4.

Do not skip 6.4 or 7.4 on the way through. The deprecation notices are the entire value of those releases for an upgrading project. Jumping straight from 6.3 to 7.4 means every removal arrives at once as a fatal error rather than as a log line you can work through.

Finding your deprecations

Three places, in order of usefulness.

The web profiler. Run the app in dev and look at the logs panel. Deprecations appear there as you exercise the code. Cheap, immediate, and only covers the paths you actually visit.

Your test suite. This is the one that scales. The PHPUnit bridge collects deprecations across the whole run and prints a summary:

composer require --dev symfony/phpunit-bridge
# phpunit.xml.dist
<server name="SYMFONY_DEPRECATIONS_HELPER" value="max[total]=0"/>

That makes the test suite fail if any deprecation is triggered. Set it once you are near zero, not at the start, or you will simply have a permanently red build. Before that, use max[total]=999 and watch the number come down.

Rector. Automates a good share of the mechanical fixes:

composer require --dev rector/rector
use Rector\Symfony\Set\SymfonyLevelSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src'])
    ->withSets([SymfonyLevelSetList::UP_TO_SYMFONY_74]);

Read every diff. Rector is good at renames and signature changes and less good at anything requiring judgement. Treat the output as a first pass rather than a result.

The category people miss

Deprecations come in two kinds and only one of them is your code.

Direct deprecations are in your application. You fix them.

Indirect deprecations come from bundles in vendor/. You cannot fix them by editing your own code. Usually the answer is to upgrade the bundle, because maintainers have had two years to prepare. Sometimes the bundle is abandoned, and then you have a decision to make that is bigger than a version bump.

Find them early. An abandoned bundle blocking a major upgrade is the thing that turns a two-week job into a two-month one, and you want to know in month one.

composer outdated --direct
composer why some/bundle

What actually bites

Four things, based on where the friction concentrates rather than on the length of the changelog.

Abandoned bundles

The obvious one is SensioFrameworkExtraBundle, abandoned back in 6.2. If your codebase still has it, that is a migration in its own right, and it is not purely mechanical. @ParamConverter was two features with two different replacements, and one of them changes behaviour in a way that is easy to miss.

Audit for abandoned packages before planning anything:

composer show --direct --format=json | grep -i abandoned

Doctrine and PHP 8.4 lazy objects

This is the largest ecosystem change in the Symfony 8 move, and it is not really a Symfony change at all.

PHP 8.4 added native lazy objects. Doctrine can now use them instead of generating proxy classes into a cache directory at build time. That removes a whole category of deployment awkwardness, and it means the proxy generation step in your build pipeline stops being needed.

If you have anything that depends on generated proxy classes existing on disk, or a deployment step that warms them, that is worth finding before you upgrade rather than after.

PHP version, twice

Symfony 7 needs PHP 8.2. Symfony 8 needs PHP 8.4. So this is two PHP upgrades, not one, and they may not be on the same schedule as your framework work.

Do the PHP upgrade first and separately. Debugging a PHP incompatibility and a Symfony deprecation in the same change is unpleasant, and PHP upgrades are usually the smaller and better-understood job.

Annotations

If any part of your codebase still uses Doctrine annotations rather than PHP attributes, that has to be resolved. Attributes have been the way forward since PHP 8.0, and the annotation reader has been progressively removed across the ecosystem.

This is mechanical and Rector handles most of it, but it touches every file that has a route, an entity mapping, or a validation constraint. Budget for the review, not the edit.

7.4 or 8.x?

Once you are on 7.4 with no deprecations, both doors are open. The choice depends on what the application is.

Stay on 7.4 if it is a long-lived business application you want to touch rarely. Bug fixes until November 2028, security until November 2029. That is three more years of not thinking about it.

Go to 8.x if you upgrade regularly anyway and want the newer features. Standard releases get eight months each, so this commits you to an upgrade roughly twice a year. Symfony 8.0 has already reached the end of its window; 8.1 is the current standard release.

For most teams with a production application and other work to do, 7.4 is the right answer, and 8.4 LTS in late 2027 is the next real decision point. The upgrade you should be doing now is to 7.4. Reaching zero deprecations there is what makes the 8.x door cheap to open whenever you want it.

What to do this month

If you are on 6.4 and November 2026 is approaching, the first three steps cost almost nothing and tell you the size of the job:

  1. Install symfony/phpunit-bridge and get a deprecation count. Even a rough number from a partial test suite tells you whether this is days or months.
  2. Run composer show --direct and look for anything abandoned. This is your critical path.
  3. Check what PHP version your hosting will support, and when. That sets your ceiling regardless of what you do in the codebase.

Then work the deprecation count down while still on 6.4. The version bump is the last and smallest part of the job, which is exactly how Symfony designed it.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Please share this article on your favorite website or platform.