Symfony 6.4 ne recevra plus de corrections de bugs après novembre 2026. Il reste couvert pour la sécurité jusqu'en novembre 2027, ce qui laisse un an pour planifier la suite. Deux cibles sont possibles : Symfony 7.4 LTS ou la branche 8.x. La méthode technique est presque la même, mais le rythme de maintenance qui suit n'a rien à voir. Voici comment choisir, puis la méthode de migration étape par étape.

Le calendrier officiel

Les dates ci-dessous viennent de symfony.com/releases, consulté à la rédaction.

Version PHP minimum Fin des corrections de bugs Fin des correctifs de sécurité
6.4 LTS 8.1 novembre 2026 novembre 2027
7.4 LTS 8.2 novembre 2028 novembre 2029
8.0 8.4 juillet 2026 (terminé) juillet 2026
8.1 8.4 janvier 2027 janvier 2027
8.2 (novembre 2026) 8.4 juillet 2027 juillet 2027
8.4 LTS (prévue en novembre 2027) 8.4 novembre 2030 (prévision) novembre 2031 (prévision)

Deux points à retenir. D'abord, 7.4 et 8.0 ont été publiées ensemble en novembre 2025 avec les mêmes fonctionnalités : 8.0 est 7.4 sans les couches de compatibilité des éléments dépréciés. Ensuite, les versions mineures non LTS ne sont maintenues que huit mois : choisir la branche 8 aujourd'hui, c'est s'engager à monter de version mineure tous les six mois jusqu'à 8.4 LTS.

Ces dates sont aussi sur la page fins de vie Drupal, PHP et Symfony, avec un calendrier à ajouter à votre agenda.

7.4 ou 8.x : les critères

Critère Plutôt 7.4 LTS Plutôt 8.x
Rythme de maintenance souhaité Une montée majeure tous les 3-4 ans Une montée mineure tous les 6 mois
Version de PHP disponible en production 8.2 ou 8.3 8.4 ou plus
Doctrine ORM 2 encore présent Déjà en ORM 3 et DBAL 4
Bundles tiers Certains pas encore compatibles 8 Compatibilité 8 vérifiée pour chacun
Équipe Peu de temps dédié à la maintenance Équipe active, CI solide

Pour la plupart des applications métier, 7.4 LTS est la cible raisonnable : sécurité assurée jusqu'en 2029, pas d'exigence PHP 8.4 immédiate, et le passage ultérieur vers 8.4 LTS se fera avec la même méthode. La branche 8 se justifie pour une équipe qui livre en continu et veut profiter des nouveautés sans attendre.

Une précision sur PHP : 7.4 accepte PHP 8.2, mais selon php.net PHP 8.2 perd son support de sécurité le 31 décembre 2026 (voir PHP 8.2 en fin de support). Visez PHP 8.3 au minimum, 8.4 de préférence, même en restant sur 7.4.

Étape 1 : éliminer les dépréciations en 6.4

Symfony applique une règle stricte de rétrocompatibilité : une application qui ne déclenche plus aucune dépréciation en 6.4 fonctionne en 7.x. L'essentiel du travail se fait donc avant de changer de version. Pour viser 8.x, la même opération se répète ensuite sur 7.4 : les dépréciations introduites en 7.x doivent à leur tour disparaître.

Les dépréciations du conteneur

php bin/console debug:container --deprecations

Cette commande affiche les dépréciations levées pendant la compilation du conteneur et le préchauffage du cache : services mal déclarés, options de configuration obsolètes, bundles qui utilisent des API retirées. Ajoutez-la à la CI pendant toute la durée du chantier.

Les dépréciations à l'exécution

Elles n'apparaissent que lorsque le code concerné s'exécute. Deux sources :

  • le profileur en environnement de développement (onglet Logs, filtre dépréciations) ;
  • un fichier de log dédié, alimenté par le canal deprecation de Monolog, que l'on laisse tourner en recette pendant quelques jours :
# config/packages/monolog.yaml
when@dev:
    monolog:
        handlers:
            deprecation:
                type: stream
                channels: [deprecation]
                path: "%kernel.logs_dir%/deprecations.log"

Les tests avec symfony/phpunit-bridge

composer require --dev symfony/phpunit-bridge

Le bridge produit un rapport des dépréciations en fin d'exécution des tests. La variable SYMFONY_DEPRECATIONS_HELPER permet de le régler, par exemple pour faire échouer les tests sur toute dépréciation déclenchée par votre code ou par ses appels directs aux dépendances, tout en tolérant les dépréciations internes aux dépendances :

SYMFONY_DEPRECATIONS_HELPER='max[self]=0&max[direct]=0' ./vendor/bin/simple-phpunit

Sur un gros projet, l'option generateBaseline=true&baselineFile=./tests/allowed.json fige les dépréciations existantes pour empêcher d'en ajouter de nouvelles pendant que l'on traite le stock. Si votre projet est passé à PHPUnit 10 ou plus, vérifiez le mode d'intégration recommandé pour votre version dans la documentation du bridge : le fonctionnement diffère de PHPUnit 9.

Le rapport distingue les dépréciations self (votre code), direct (votre code appelle une dépendance dépréciée) et indirect (une dépendance en appelle une autre). Les indirectes se règlent en général en mettant à jour les bundles, pas en touchant votre code.

Étape 2 : automatiser avec Rector

Rector corrige une bonne partie des dépréciations mécaniques : signatures, attributs, noms de classes, options renommées. Avec Rector 2, la configuration mise en avant par la documentation, withComposerBased(), lit les versions installées et charge les règles adaptées :

<?php
// rector.php
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
    ->withComposerBased(symfony: true, doctrine: true, twig: true)
    ->withPreparedSets(symfonyCodeQuality: true);
vendor/bin/rector composer-based   # liste les règles actives (Rector 2.6 ou plus)
vendor/bin/rector process --dry-run

Les ensembles de règles par version (SymfonySetList) restent utilisables avec withSets() sur une configuration plus ancienne. Relisez chaque diff : Rector est fiable sur les transformations syntaxiques, pas sur l'intention métier.

Étape 3 : monter les paquets

La méthode décrite par la documentation Symfony consiste à remplacer 6.4.* par 7.4.* dans les contraintes symfony/* du composer.json, et à mettre à jour extra.symfony.require, que Flex utilise pour contraindre toutes les briques d'un coup :

{
    "extra": {
        "symfony": {
            "require": "7.4.*"
        }
    }
}
composer update "symfony/*" --with-all-dependencies

On peut aller directement de 6.4 à 7.4 sans passer par 7.0 à 7.3. Quand Composer refuse, la commande why-not indique quel paquet bloque :

composer why-not symfony/framework-bundle "7.4.*"

C'est là qu'apparaissent les bundles tiers non maintenus. Trois issues possibles : une nouvelle version majeure existe (avec ses propres ruptures), un fork maintenu existe, ou il faut remplacer le bundle par quelques services écrits à la main. Identifiez ces cas avant de chiffrer le chantier : ce sont eux qui font déraper les estimations.

Étape 4 : mettre à jour les recettes Flex

Les recettes génèrent les fichiers de configuration de chaque bundle. Elles évoluent avec les versions et ne sont pas mises à jour automatiquement.

composer recipes            # liste les recettes qui ont une mise à jour
composer recipes:update symfony/framework-bundle

La commande applique la nouvelle version sous forme de patch, avec des conflits à résoudre comme dans Git. Committez avant chaque mise à jour de recette, et traitez-les une par une.

Le cas Doctrine : ORM 2 ou 3 ?

Doctrine pèse lourd dans le choix de Symfony 8. D'après les contraintes publiées sur Packagist au moment de la rédaction, la branche 2.x de DoctrineBundle accepte Symfony 6.4 et 7.x et fonctionne avec ORM 2 comme avec ORM 3. Pour Symfony 8, il faut la branche 3.x de DoctrineBundle, qui exige PHP 8.4, DBAL 4 et ORM 3. Vérifiez ces contraintes à la date de votre chantier, elles évoluent avec les versions.

Concrètement :

  • cible 7.4 : vous pouvez rester en ORM 2 et DoctrineBundle 2.x, et traiter ORM 3 plus tard ;
  • cible 8.x : la montée en ORM 3 et DBAL 4 fait partie du chantier. Elle a ses propres ruptures (API retirées, changements de types et de mapping), à préparer avec les dépréciations Doctrine et les règles Rector correspondantes.

ORM 3 est la branche sur laquelle Doctrine concentre ses évolutions. Même en ciblant 7.4, faire disparaître les dépréciations Doctrine au passage prépare la montée suivante.

Autres ruptures à anticiper pour Symfony 8

  • La configuration XML de l'application (services, routes, configuration des bundles dans config/) est dépréciée depuis 7.4 et retirée en 8.0. YAML et PHP restent supportés. Les mappings Doctrine, les métadonnées de validation et de sérialisation en XML ne sont pas concernés.
  • Les fichiers UPGRADE-7.0.md à UPGRADE-8.0.md du dépôt Symfony listent les ruptures composant par composant. Lisez ceux des composants que vous utilisez réellement.

Stratégie de branches

Sur une application en production qui continue d'évoluer, je sépare le chantier en deux temps :

  1. Sur la branche principale, tout ce qui est compatible avec 6.4 : corrections des dépréciations, passage Rector, montée de PHP, mises à jour des bundles dans leur dernière version compatible 6.4. Ces changements partent en production au fil de l'eau, par petits lots.
  2. Sur une branche courte dédiée, uniquement le changement de contrainte 7.4.*, les recettes et les derniers ajustements. Plus l'étape 1 a été menée loin, plus cette branche est petite et vite fusionnée.

Une CI qui fait tourner les tests sur les deux versions de PHP (actuelle et cible) pendant la transition sécurise l'ensemble. La branche longue qui diverge pendant trois mois est le scénario à éviter.

Par où commencer

Mesurez l'écart : nombre de dépréciations au conteneur et en tests, bundles bloquants, version de Doctrine, version de PHP en production. Ces quatre informations suffisent pour choisir entre 7.4 et 8.x et pour chiffrer le chantier. C'est ce que couvre un audit flash ; la page Symfony détaille les montées de version et la maintenance d'applications, domaine sur lequel j'ai notamment assuré le pilotage technique d'un projet Symfony 5 en mission freelance pour CONSERTO, avec une équipe de cinq développeurs.