
September 07, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
Migrating a Symfony 4 app to Symfony 7 is not a single composer bump. Symfony dropped one major version per year after 4.x, and each jump removes APIs your 4.x code still calls. You must raise PHP, clear deprecations, and upgrade through 5, 6, and 7 in order. This guide walks through the path I use on production Symfony apps, including the multi-environment config and deployment checks that keep staging honest before production.
What is the correct upgrade path when migrating a Symfony 4 app to Symfony 7?
Symfony does not support jumping from 4.x straight to 7.x. The supported route is 4.4 LTS → 5.4 → 6.4 LTS → 7.x. Each stop exposes deprecations that become hard errors in the next major.
Symfony 4.4 reached end of life in November 2023. If you still run 4.4, treat security patches as gone and plan the migration as risk reduction, not optional cleanup. Symfony 6.4 LTS is supported until November 2027. Symfony 7.x is the current stable line in 2026, with Symfony 8.1 available if you want the newest APIs and PHP 8.4.1 minimum.
On client projects I maintain, the first decision is target version: stop at 6.4 LTS for maximum stability, or land on 7.x for current features. This article targets Symfony 7 because that is what most teams ask for in 2026.
Plan for three to six months on a medium codebase with custom bundles and legacy controllers. A small API with good test coverage can finish in weeks. Budget time for third-party packages that never updated past Symfony 5.
How do you prepare a Symfony 4 codebase before starting the upgrade?
Preparation saves more time than any composer flag. You want a clean git baseline, a working CI pipeline, and a list of every deprecation before you touch version constraints.
Audit the current stack
Record PHP version, Symfony patch level, Doctrine ORM version, and every bundle in composer.json. Export production environment variables and compare them against .env and .env.local. Misaligned env files cause more post-upgrade failures than framework changes.
Run the built-in deprecation helper on Symfony 4.4 first:
composer require --dev symfony/phpunit-bridge
SYMFONY_DEPRECATIONS_HELPER=max[total]=0 vendor/bin/simple-phpunit Set max[total]=0 only after you have cleared existing noise. Start with weak mode to collect a full list without failing the build.
Establish safety nets
- Ensure PHPUnit or Pest covers critical paths — checkout, auth, admin CRUD, API endpoints.
- Clone production data into staging with anonymised PII if regulations require it.
- Enable the Symfony test suite in CI so every branch runs
bin/console lint:containerandbin/console doctrine:schema:validate. - Document custom compiler passes, event subscribers, and security voters. These break silently more often than controllers.
If the app uses hexagonal architecture, domain code may survive untouched. Infrastructure adapters around Doctrine, Messenger, and HTTP clients need the most attention.
What PHP version do you need before upgrading to Symfony 7?
Symfony 7 requires PHP 8.2 or higher. Symfony 4.4 ran on PHP 7.1. That gap is the hardest part of many migrations.
Raise PHP on a branch before or alongside the Symfony 5 upgrade. PHP 8.0 removed the each() function and changed error handling. PHP 8.1 added enums and readonly properties. PHP 8.2 deprecated dynamic properties. PHP 8.3 and 8.4 add further type strictness.
On Ubuntu 24 servers I run PHP 8.3 or 8.4 alongside older versions using update-alternatives. Symfony 7 works fine on PHP 8.5 when you are ready. Symfony 8.1 requires PHP 8.4.1 minimum if you plan to continue past 7.x later.
Validate extensions before switching FPM pools:
php -m | grep -E 'intl|mbstring|xml|curl|zip|pdo_mysql'
composer check-platform-reqs Doctrine ORM 2.x does not run on Symfony 7. Plan a move to Doctrine ORM 3.x during the Symfony 6 step. Review the official Doctrine ORM upgrade guide for removed annotations and mapping changes.
| Symfony version | Minimum PHP | Support status (2026) | Notes |
|---|---|---|---|
| 4.4 LTS | 7.1.3 | End of life | Starting point for most legacy apps |
| 5.4 | 7.2.5 | End of life | Transitional; fix 4.x deprecations here |
| 6.4 LTS | 8.1 | Active LTS to Nov 2027 | Doctrine ORM 3, native types |
| 7.x | 8.2 | Active stable | Target for this migration |
| 8.1 | 8.4.1 | Current major | Optional next step after 7.x |
How do you upgrade Symfony dependencies step by step?
Use the Symfony flex recipes and official upgrade tooling. The Symfony major version upgrade guide is the primary reference. Work on a dedicated branch. Merge only when tests pass at each major boundary.
Step 1: Symfony 4.4 → 5.4
Update the extra Symfony constraint in composer.json:
"extra": {
"symfony": {
"require": "5.4.*"
}
} Then run:
composer update "symfony/*" --with-all-dependencies
bin/console cache:clear
bin/console debug:container --deprecations Common fixes at this stage:
- Replace
guardauthenticators with the new authenticator manager. See the Symfony security firewall guide for current YAML structure. - Move
services.ymldefaults from_defaultsautowire-only to explicitautoconfigure: truewhere needed. - Replace
SwiftMailerwithsymfony/mailerandsymfony/mime. - Update
framework.yaml— removetemplating, confirmcsrf_protectionandsessionblocks.
Step 2: Symfony 5.4 → 6.4
Raise PHP to 8.1 minimum first. Update the constraint to 6.4.* and run composer update again.
Doctrine changes hit hard here. Replace annotations with PHP 8 attributes unless you keep doctrine/annotations temporarily. Run Doctrine migrations in a transaction on staging before production.
Remove @Route annotations from controllers unless you use symfony/routing attributes. The bin/console debug:router output should match your sitemap and API docs exactly.
Step 3: Symfony 6.4 → 7.x
Confirm PHP 8.2+. Set the constraint to 7.4.* or the latest 7.x patch your team approves:
"extra": {
"symfony": {
"require": "7.4.*"
}
} composer update "symfony/*" --with-all-dependencies
composer outdated "symfony/*"
bin/console about Symfony 7 removes more legacy class aliases. Watch for:
UserInterfacechanges in security — password upgrade interfaces moved.- Removed support for XML validation mapping in some components.
- Console command default name changes — update cron entries that call commands by old names.
framework.messengerrouting if you use async — validate against the Messenger async guide.
Use the JSON formatter when debugging API responses that break after serializer changes. Symfony 7 tightens normalisation defaults compared to Symfony 4.
What breaking changes hit Symfony 4 apps hardest in Symfony 7?
Not every deprecation screams in logs. These areas cause production incidents if you rush the final jump.
Security and authentication
Symfony 4 often used fos/user-bundle or custom guard authenticators. Symfony 7 expects the authenticator system with LoginFormAuthenticator or custom authenticators implementing AuthenticatorInterface. Password hashers moved to password_hashers in security config. Test login, logout, remember-me, and API token auth on staging with real cookies.
Forms, validation, and serialization
Form types that relied on ChoiceType with choices_as_values need rewriting. Validation groups still work, but annotation-based constraints should become PHP attributes. The Symfony serializer ignores null fields differently unless you configure skip_null_values explicitly.
Third-party bundles
Check Packagist for Symfony 7 compatible releases before you start. Abandoned bundles force replacement:
- SwiftMailer → Symfony Mailer (done by Symfony 6).
- SensioFrameworkExtraBundle → native attributes in Symfony 6+.
- Old admin generators → EasyAdmin 4.x or custom CRUD.
When a bundle has no update, extract the 200 lines you actually use into a project service. I have done this on legal-tech portals where a PDF bundle stalled at Symfony 5. The fork lived longer than expected, but it unblocked the upgrade.
Caching and performance
Symfony 7 defaults favour cache.system and Redis adapters over APCu-only setups. If you use Redis, align pool config with the Symfony cache component guide. Warm caches after deploy:
APP_ENV=prod APP_DEBUG=0 bin/console cache:clear
APP_ENV=prod APP_DEBUG=0 bin/console cache:warmup Reload PHP-FPM after deploy so opcache picks up new files. I use the same pattern described in Symfony deployment on Ubuntu VPS — symlink release, warmup, reload FPM, run smoke tests.
How do you test and deploy after reaching Symfony 7?
Testing proves the migration worked. Deployment puts it in front of users without downtime surprises.
Automated testing layers
- Unit tests — domain services, validators, custom constraints.
- Integration tests — Doctrine repositories, Messenger handlers,
WebTestCasefor forms. - Contract tests — compare API JSON schemas against mobile or SPA clients.
- Load tests — run k6 load tests on staging at 2× expected traffic.
Run bin/console lint:yaml config/ and bin/console lint:twig templates/. Broken Twig after upgrade usually means deprecated filters from old symfony/twig-bridge extensions.
Production cutover
Schedule during low traffic. Nepal-based businesses often prefer late evening or early morning windows outside Dashain/Tihar peaks if those affect their users.
Deployment checklist:
- Put app in maintenance mode if you cannot run blue-green.
- Pull release tag, run
composer install --no-dev --optimize-autoloaderwith Composer 2.10. - Run pending migrations:
bin/console doctrine:migrations:migrate --no-interaction. - Clear and warmup prod cache.
- Reload PHP-FPM and verify
bin/console aboutreports Symfony 7.x. - Hit health-check URLs, login flow, one write operation, one queued job.
For teams without in-house DevOps, professional website migration support covers PHP version changes, zero-downtime deploys, and rollback planning. Similar work applies to enterprise Symfony applications with document workflows and payment callbacks.
Keep Symfony 6.4 LTS as a rollback tag in git if the 7.x deploy fails. Restore the previous release directory, reload FPM, and investigate before retrying. Document the incident — the support and maintenance retainer clients sign often starts with upgrade war stories like this.
Compare Symfony against Laravel if you are deciding future greenfield work. The Symfony 7 vs Laravel 12 article covers container philosophy, hiring, and ecosystem trade-offs. Symfony wins on long-lived enterprise apps with strict domain boundaries. Laravel 13 ships on PHP 8.3 minimum if you pivot stacks entirely — that is a rewrite, not a migration.
Reference projects with complex workflows — like Mijar Law Associates client portal or Adventure Third Pole Trek booking CRM — benefit from incremental upgrades because they cannot afford multi-week downtime. The same incremental discipline applies to Symfony 4 codebases even when the UI looks fine.
Apply twelve-factor principles during the upgrade: externalise config, treat logs as streams, and keep dev/prod parity. Upgrades expose env drift faster than any audit spreadsheet.
For automated refactors, Rector with rector/rector-symfony removes hundreds of manual edits. Run it in small commits:
composer require --dev rector/rector rector/rector-symfony
vendor/bin/rector process src/ --dry-run
vendor/bin/rector process src/ Review every Rector diff. It misses business-specific edge cases. Pair Rector with phpstan at level 6 or higher once you reach Symfony 6.
After migration, schedule testing and optimisation to catch N+1 queries Doctrine 3 surfaces under load. Symfony 4 apps often hid slow queries behind APCu. Symfony 7 with Redis expects you to fix the database layer properly.
If your app exposes REST or GraphQL, validate responses against the API Platform guide if you adopt or already use API Platform. Version your API URL prefix so mobile clients can fall back during cutover.
Console commands in cron deserve a pass too. The Symfony console commands guide documents naming changes that break Sunday-night batch jobs silently.
Instrument with OpenTelemetry if you lack visibility. The OpenTelemetry instrumentation guide helps compare error rates before and after migration using real trace data instead of guesswork.
On the PHP side, read the official PHP 8.2 migration notes for language-level breaks your static analysis might miss.
Key Takeaways
- Upgrade sequentially through Symfony 5.4 and 6.4 LTS — never jump directly from 4.4 to 7.x.
- Raise PHP to 8.2+ before the final Symfony 7 composer update and run
composer check-platform-reqs. - Fix every deprecation at each major boundary using
SYMFONY_DEPRECATIONS_HELPERand Rector. - Replace abandoned bundles (SwiftMailer, SensioFrameworkExtraBundle) early in the 5.x step.
- Deploy with cache warmup, PHP-FPM reload, migration run, and 24-hour log monitoring.
- Keep a Symfony 6.4 rollback tag until production proves stable on Symfony 7.
People Also Ask
Can you skip Symfony 5 and 6 and upgrade directly to Symfony 7?
No. Symfony's backward-compatibility policy removes deprecated code each major release. A direct jump leaves hundreds of unresolved breaks in security, routing, and dependency injection. The supported path is 4.4 → 5.4 → 6.4 → 7.x with deprecation fixes at each stop.
How long does migrating a Symfony 4 app to Symfony 7 take?
A small app with good tests and maintained bundles can finish in four to eight weeks. Medium enterprise apps with custom authentication, Doctrine 2 mappings, and abandoned bundles typically need three to six months. Timeline depends on test coverage and how many deprecations you ignored while on 4.4.
Is Symfony 6.4 LTS enough, or do you need Symfony 7?
Symfony 6.4 LTS is supported until November 2027 and suits teams that want stability without chasing the latest APIs. Choose Symfony 7 if you need current component features, longer support runway beyond 6.4, or plan to eventually move to Symfony 8.1 on PHP 8.4.1.
What happens to Doctrine ORM 2 during the upgrade?
Doctrine ORM 2.x does not support Symfony 7. Upgrade to Doctrine ORM 3.x during the Symfony 6 step. Expect mapping changes from annotations to PHP 8 attributes, namespace updates, and stricter type handling in repositories.
Plan your Symfony upgrade with a clear runway
Migrating a Symfony 4 app to Symfony 7 is predictable when you treat it as a series of small, tested releases rather than one risky launch weekend. Audit deprecations today, raise PHP on staging this week, and walk the major versions one at a time. Your future self — and every cron job on the server — will thank you.
Need help scoping a Symfony upgrade, PHP lift, or zero-downtime deploy? Contact us to review your codebase and build a migration plan that fits your traffic and budget. For ongoing work after cutover, see support and maintenance services and explore related Symfony content on the blog.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.


