
Symfony 7.4 LTS - The Last Stop Before Symfony 8
The LTS That Matters
Every two years, Symfony ships a Long-Term Support release. These are the versions you actually want to run in production.
Symfony 7.4 is that release - dropping late November 2025. You get:
- Bug fixes until November 2028 (3 years)
- Security fixes until November 2029 (4 years)
But here's what makes this release interesting: Symfony 8.0 launches at the same time with identical features, but 8.0 removes all deprecated code and bumps minimum requirements.
Think of 7.4 as your bridge. Upgrade to 7.4, fix all deprecation warnings, then jumping to 8.0 is trivial.
XML Configuration: It's Over
The big one: XML configuration is officially deprecated in 7.4 and completely gone in 8.0.
If you're still writing this:
<!-- services.xml --> <?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services"> <services> <service id="App\Service\UserService" autowire="true" /> </services> </container>
Time to migrate. Your options: YAML (default) or PHP configuration.
YAML with JSON Schemas
YAML now has IDE validation:
# config/services.yaml # yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json parameters: app.api_key: '%env(API_KEY)%' services: _defaults: autowire: true autoconfigure: true App\: resource: '../src/' exclude: - '../src/DependencyInjection/' - '../src/Entity/'
Your IDE will now autocomplete and validate configuration. No more typos breaking your builds.
PHP Configuration (Type-Safe)
Or go full type-safe:
// config/packages/framework.php namespace Symfony\Config; return static function (FrameworkConfig $framework) { $framework ->secret(env('APP_SECRET')) ->httpCache() ->enabled(true); $framework ->session() ->handlerId(null) ->cookieSecure('auto') ->cookieSamesite('lax'); };
Autocomplete everywhere. Type checking at the language level. No runtime surprises from config typos.
For reusable bundles still on XML, Symfony provides a migration tool to convert XML → PHP automatically.
UUID v7: Better Database Performance
Symfony's UUID component now defaults to UUIDv7 instead of v4.
use Symfony\Component\Uid\Factory\UuidFactory; class ProductService { public function __construct( private UuidFactory $uuidFactory, ) {} public function createProduct(): void { // Generates UUIDv7 by default (time-ordered) $uuid = $this->uuidFactory->create(); // Or be explicit $uuid = $this->uuidFactory->timeBased()->create(); } }
Why this matters:
UUIDv7 includes a timestamp (Unix Epoch + microseconds) in the UUID itself. This means:
- Better database indexing (values are naturally ordered)
- Less index fragmentation in high-volume tables
- 10% faster generation compared to v4
For a typical CRUD app? You won't notice. For apps with millions of records? This adds up.
MockUuidFactory for Testing
Testing code that generates UUIDs used to be painful. Not anymore:
use Symfony\Component\Uid\Factory\MockUuidFactory; use Symfony\Component\Uid\UuidV4; class UserServiceTest extends TestCase { public function testCreateUser(): void { $factory = new MockUuidFactory([ UuidV4::fromString('11111111-1111-4111-8111-111111111111'), UuidV4::fromString('22222222-2222-4222-8222-222222222222'), ]); $service = new UserService($factory); $userId1 = $service->createUserId(); $userId2 = $service->createUserId(); $this->assertSame('11111111-1111-4111-8111-111111111111', $userId1); $this->assertSame('22222222-2222-4222-8222-222222222222', $userId2); } }
Deterministic UUIDs in tests. Finally.
Security Voter Improvements
This is a nice DX upgrade. You can now get detailed feedback about authorization decisions:
{% set decision = access_decision('post_edit', post) %} {% if decision.isGranted() %} <a href="{{ path('post_edit', {id: post.id}) }}">Edit</a> {% else %} <p class="error">{{ decision.message }}</p> {# Shows actual reason: "You must be the author" #} {% endif %}
Instead of just true/false, you get context about why access was denied.
In your voter:
use Symfony\Component\Security\Core\Authorization\Voter\Vote; class BlogPostVoter extends Voter { protected function voteOnAttribute( string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null ): bool { $user = $token->getUser(); if (!$user instanceof User) { $vote?->extraData->set('reason', 'Must be logged in'); return false; } if ($subject->getAuthor() !== $user) { $vote?->extraData->set('reason', 'You must be the author'); return false; } return true; } }
Better error messages for users, less "why can't I do this?" support tickets.
HTTP Client Caching: RFC 9111 Compliant
Symfony's HTTP client gets real caching:
# config/packages/framework.yaml framework: cache: pools: api_cache_pool: adapter: cache.adapter.redis_tag_aware tags: true http_client: scoped_clients: api.client: base_uri: 'https://api.example.com' caching: cache_pool: api_cache_pool
The client now respects HTTP cache headers (Cache-Control, ETag, etc.) automatically. No more manual cache logic for API clients.
Plus tag-aware caching means you can invalidate related cached responses together:
$cache->invalidateTags(['user_123']);
All cached API responses tagged with that user are instantly gone.
ControllerHelper: Helpers Without Inheritance
I never liked extending AbstractController just to get helper methods. Symfony 7.4 fixes this:
use Symfony\Bundle\FrameworkBundle\Controller\ControllerHelper; class MyInvokableController { public function __construct( private ControllerHelper $helper, ) {} public function __invoke(): Response { // All the helper methods, no inheritance return $this->helper->render('template.html.twig', [ 'data' => $someData, ]); } }
Composition over inheritance. Modern PHP practices.
What Gets Deprecated
These work in 7.4 with deprecation warnings, gone in 8.0:
- XML configuration for everything (services, routes, validation, etc.)
- Fluent PHP format for semantic config
- Session config options following PHP 8.4's deprecations
!taggedYAML tag → use!tagged_iteratorinstead- Empty user identifiers in UserBadge constructor
TranslatableMessage::__toString()→ usetrans()method
If you're on Symfony 6.4 or 7.x already, you've probably seen warnings about most of these.
Upgrade Path: The Smart Way
Don't jump from 6.4 to 7.4 in one go.
Here's the plan:
- Upgrade to Symfony 6.4 LTS (if not already)
- Run
bin/console debug:container --deprecations - Fix ALL deprecation warnings
- Upgrade to 7.4 LTS (smooth sailing)
- Fix new 7.4 deprecations
- Upgrade to 8.0 when ready (trivial at this point)
Symfony deprecations are well-documented. They tell you exactly what to change. Don't ignore them.
Performance Notes
Symfony 7.4 doesn't have massive performance improvements over 7.3. The big wins came earlier:
- Symfony 6.2: Native attributes instead of annotations
- Symfony 6.3: Various profiler and cache improvements
- Symfony 7.0: PHP 8.2+ features
But the UUID v7 default helps high-volume apps. The HTTP client caching reduces external API calls. Small improvements that add up.
What I'm Actually Using This For
I've got three apps on Symfony 6.4 LTS right now. All three are getting upgraded to 7.4 in December:
Why?
- 4 years of security updates vs 6.4's remaining 2 years
- Better DX with the new UUID factory
- HTTP client caching will reduce our API costs
- Cleaner controller code with ControllerHelper
Why not wait for 8.0?
- 7.4 gives me time to fix deprecations gradually
- Production apps don't need to be on the bleeding edge
- LTS releases are safer for production
When to Upgrade
New projects: Use Symfony 7.4 LTS when it drops (late November).
Existing apps on 6.4 LTS: Upgrade within the next 3-6 months. You have until November 2026 for security updates, but why wait?
Existing apps on 7.x: Upgrade to 7.4 as soon as it's stable. Small changes, long-term support.
Existing apps on 5.x or older: Upgrade to 6.4 LTS first. Jumping multiple major versions is asking for pain.
The Bottom Line
Symfony 7.4 is a stabilization release with long-term support. Not flashy, but solid.
The XML deprecation will affect some teams. The UUID v7 default is a smart move. The HTTP client improvements are genuinely useful.
But the real value? 4 years of security updates. That's what LTS is about.
If you run Symfony in production, 7.4 is the version you want. Mark your calendar for late November.
Resources
- Symfony 7.4 Release Page
- Symfony 8.0 Release Page
- Living on the Edge Blog Posts
- Upgrade Guide (when released)
Plan ahead. LTS releases matter. 🚀