Synapsea
Symfony · Modernization

Symfony 6.4 to 7.4 migration: steps, risks and upgrade strategy

Why move from the 6.4 LTS to the 7.4 LTS before the end of 2027, what actually changes, how to handle deprecations and dependencies, and the test plan that keeps the upgrade boring.

By the Synapsea team · · 4 min read

Symfony 6.4 and 7.4 are both long-term support releases. 6.4 stops receiving bug fixes on November 30, 2026 and security fixes on November 30, 2027; 7.4 is maintained until November 30, 2028 (bugs) and November 30, 2029 (security). For an application that has to live a few more years, the question is not whether to migrate but when and how. Here is the method we use.

1. What changes between 6.4 and 7.4

Symfony's rule has been stable since 3.x: a major release (7.0) adds no feature over the last previous minor (6.4); it only removes the deprecation layers. 7.1 through 7.4 then add features and, in turn, deprecate things. The same rule applies to 8.0, which "equals 7.4 minus deprecations", in the Symfony team's own words.

Three practical consequences:

  • The PHP floor rises. Symfony 6.4 runs on PHP 8.1 or later, Symfony 7.x requires PHP 8.2 or later, Symfony 8.0 requires PHP 8.4. On the PHP side, 8.2 and 8.3 only receive security fixes (until December 31, 2026 and 2027 respectively); 8.4 and 8.5 are in active support. Targeting PHP 8.4 during the migration avoids a second operation a year later.
  • Everything deprecated in 6.4 is gone in 7.0: method signatures, configuration options, services, annotations in favor of PHP attributes.
  • Third-party dependencies must follow. A bundle that declares symfony/framework-bundle: ^6.0 blocks the 7.x install.

2. Preparing on 6.4

The upgrade is won before the version number changes.

  1. Empty the deprecation log. Symfony's recommended command is simple:

    php bin/phpunit --display-deprecations
    

    Direct deprecations come from your code and are yours to fix; indirect ones come from vendor/ and should be reported (or worked around with an update) upstream. Without a test suite, smoke tests on the main URLs already surface most of them.

  2. Inventory dependencies. composer outdated --direct and composer why-not symfony/symfony 7.4.* immediately tell you which packages are blocking. Each blocker becomes a task: update, replace or, rarely, a temporary fork.

  3. Move to PHP 8.2 at minimum, ideally 8.4, while still on 6.4. This isolates PHP-related issues (stricter typing, function deprecations) from Symfony-related ones.

  4. Automate what can be automated. Rector ships rule sets that follow the installed Symfony version:

    // rector.php
    use Rector\Config\RectorConfig;
    
    return RectorConfig::configure()
        ->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
        ->withPhpSets()
        ->withComposerBased(symfony: true, doctrine: true, phpunit: true);
    

    vendor/bin/rector --dry-run previews the changes before applying them. Rector handles mechanical changes well (signatures, attributes, renames); it does not decide behavior changes for you.

3. The version jump

Once the deprecation log is empty and dependencies are aligned:

// composer.json (Symfony Flex application)
"extra": { "symfony": { "require": "7.4.*" } }
composer update "symfony/*" --with-all-dependencies

This is the procedure documented by Symfony ("Upgrading a Major Version"): the extra.symfony.require constraint sets the target version, then composer update applies it to every symfony/* package.

In practice you go package group by package group (symfony/framework-bundle, then the components you use) and rerun the test suite after each group. The areas that needed the most attention in our recent migrations:

  • serializer and validator configuration (attributes, default normalizers);
  • event listeners registered by convention, some of whose names changed;
  • the Security component: legacy authentication classes removed since 6.0 are no longer tolerated;
  • Flex recipes, to resynchronize (composer recipes:update) to get up-to-date configuration files.

4. Test plan

The risk of a migration is not that it fails loudly — it is that it succeeds quietly with different behavior. Hence a three-layer test plan:

| Layer | What it protects | When | | --- | --- | --- | | Characterization tests | Current behavior, quirks included, on critical journeys | Written before the migration | | Integration tests | APIs, database, message queues, on a production-like environment | Every batch | | Static analysis (PHPStan) | Errors introduced by signature changes | Level raised one notch after the migration |

When existing coverage is low, we do not chase a percentage: we cover the journeys that earn money or carry liability (billing, authentication, exports), then widen.

5. What about Symfony 8?

Symfony 8.0 (November 2025) and 8.1 (May 2026) are short-cycle releases (eight months). For a business application, the 7.4 LTS is the sensible target; 8.x becomes reachable as soon as the 7.4 deprecation log is empty, exactly like the 6.4 → 7.0 step. Upgrading to 7.4 is therefore not a detour: it is the required path to 8.

Takeaways

  • 6.4 gets no security fixes after November 2027; plan 7.4 now.
  • The migration is prepared on 6.4: zero deprecations, aligned dependencies, PHP 8.2 or later.
  • Rector and PHPStan speed up the mechanical work; characterization tests protect behavior.
  • Every step ships to production, in batches; no big bang.

Have a Symfony 6.4 (or older) application to upgrade? Our PHP & Symfony modernization offer starts with a preliminary diagnosis, no strings attached.

Sources: Symfony release calendar (symfony.com/releases; endoflife.date/symfony), "Preparing for Symfony 7.4 and Symfony 8.0" (symfony.com/blog), supported PHP versions (php.net/supported-versions), PHP requirements per Symfony version (zend.com/blog/symfony-php-requirements), Rector documentation (getrector.com). Dates checked on October 28, 2026.

A question about this topic in your own context?

A free 30-minute call, written answer within 2 business days.

Let's talk about your project