Skip to content

Symfony 8.0: What's New and Is It Worth Upgrading? ​

When I wrote about the evolution of Symfony back in 2024, 6.4 was the LTS everyone was standing on. Symfony 8.0 and 7.4 LTS were both released on 27 November 2025, so it's a good time to look at what the new major brings and whether you should jump straight to it.


πŸ“¦ Two Releases, One Feature Set ​

The Symfony team summed up the relationship neatly: 8.0 is 7.4 minus the deprecations. Both versions ship exactly the same features. The difference is that 7.4 still carries every deprecation layer, and 8.0 has none.

That makes the real decision about support, not features:

  • Symfony 7.4 LTS needs PHP 8.2+. Bug fixes run until November 2028 and security fixes until November 2029, but it gets no new features.
  • Symfony 8.0 needs PHP 8.4+. Like every standard release, it's maintained for eight months, until July 2026. After that you move to 8.1 (due May 2026), and so on up to the 8.4 LTS in November 2027.

✨ What's New (in 7.4 and 8.0) ​

Most of the new features came in during the 7.x cycle and were finished off in 7.4. The ones I care about most:

  • A new PHP configuration format. It's array-based and uses array shapes, so your IDE and static analyser can autocomplete and check your config. Symfony now generates a config/reference.php file that describes those shapes. YAML is still the recommended format, though.
  • Better invokable commands. Console commands no longer need to extend a base class. In 7.4 they gained #[MapInput] DTOs, backed-enum arguments, and the #[Interact] and #[Ask] attributes for interactive prompts.
  • Multi-step forms. These are built in now through the new FormFlow feature.
  • Messenger message signing. Handlers can opt in with #[AsMessageHandler(sign: true)] to reject tampered payloads.
  • Native PHP 8.4 features. In 8.0, the LazyGhostTrait and LazyProxyTrait are gone in favour of PHP's native lazy objects. On PHP 8.4, DomCrawler and HtmlSanitizer also switch to the native HTML5 parser.
php
// config/packages/security.php (new array-based format)
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

return App::config([
    'security' => [
        'firewalls' => [
            'main' => ['pattern' => '^/*', 'lazy' => true],
        ],
        'access_control' => [
            ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'],
        ],
    ],
]);

🧹 What's Been Removed ​

This is where 8.0 will bite if you haven't been watching your deprecation log. The removals most likely to affect real applications:

  • XML configuration is no longer supported, and neither is the fluent PHP config format (the Symfony\Config\* builder closures).
  • Request::get() is gone. Read from $request->attributes, $request->query or $request->request explicitly.
  • Auto-mapping Doctrine entities to controller arguments has been removed, so you now map them explicitly.
  • #[TaggedIterator] and #[TaggedLocator] are replaced by #[AutowireIterator] and #[AutowireLocator].
  • UserInterface::eraseCredentials() has been removed from the Security component.
  • Application::add() in Console is replaced by addCommand().

None of these is hard to fix on its own. Together, though, they touch config, controllers, security and DI. That's why I wouldn't attempt the jump without a deprecation-free 7.4 first.


πŸ—ΊοΈ A Sensible Upgrade Path ​

The official guidance is simple, and I agree with it: upgrade to 7.4, fix every deprecation, then move to 8.0. If you're on 6.4, that means going to 7.4 first, which brings its own set of 7.0 removals to deal with.

1. Get to the latest minor of your current major and surface deprecations. Use the profiler in dev, and run your test suite with deprecations visible. Your own code produces direct deprecations. Your dependencies produce indirect ones, and those mean upgrading or chasing a bundle maintainer.

bash
composer require --dev symfony/phpunit-bridge
php bin/phpunit --display-deprecations

2. Let Rector do the boring bits. Rector's composer-based sets read your installed Symfony version and apply only the matching rules. It won't fix everything, but it clears a lot of mechanical changes.

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

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
    ->withComposerBased(symfony: true, doctrine: true, phpunit: true);

3. Bump the constraint and update. With Flex, you set extra.symfony.require and update the Symfony packages.

bash
composer config extra.symfony.require "8.0.*"
composer update "symfony/*" --with-all-dependencies

4. Update your recipes. People skip this step, and they shouldn't. composer recipes --outdated shows what's stale, and composer recipes:update applies each recipe as a patch you can review like any Git conflict. Commit your other changes first.

5. Read UPGRADE-8.0.md for anything your tests didn't catch.


πŸ€” Is It Worth It? ​

My take: for most production apps, 7.4 LTS is the right landing spot right now. You get every new feature, PHP 8.2 compatibility and support until 2029. Bundles often need updates before a new major, so some of your dependencies may not be ready for 8.0 yet.

Go to 8.0 if you can run PHP 8.4 everywhere and you're comfortable upgrading every six months. Symfony itself recommends standard releases where possible, and minor upgrades through 8.x should be smooth. If you're still on 6.4, don't wait: its bug-fix support ends in November 2026.


🎯 Conclusion ​

Symfony 8.0 isn't a revolution. It's a cleanup that trims the deprecated code and leans properly on PHP 8.4. The real work is in 7.4: get there, get your deprecation count to zero, and 8.0 becomes a version bump rather than a project.