Migrating a Symfony 4 App to Symfony 7

Khimananda Oli 7 min read Web Development
Migrating a Symfony 4 App to Symfony 7

By Khimananda Oli | Last reviewed: August 2026

Migrating a Symfony 4 app to Symfony 7 is not a single leap but a disciplined sequence of major version upgrades. You cannot jump directly from 4.x to 7.x because Symfony enforces strict backward-compatibility breaks only at major boundaries, and skipping versions leaves unresolved deprecations that will crash your application. This guide walks you through the safe, incremental path—4→5→6→7—that I use in production environments to maintain uptime and audit readiness. Before starting any code changes, verify your server backup strategy covers both database snapshots and file system state.

Symfony 4.4PHP 7.4 / 8.0Symfony 5.4PHP 8.0 / 8.1Symfony 6.4PHP 8.1 / 8.2Symfony 7.xPHP 8.2+Fix DepsFix DepsFix Deps
Sequential migration path: each major version gate requires zero deprecations before advancing to the next Symfony release

How do you prepare a Symfony 4 project for a major version upgrade?

Preparation determines whether your migration takes days or weeks. The most common mistake I see teams make is attempting an upgrade without first achieving a clean deprecation baseline on their current LTS version. Symfony 4.4 is the last long-term support release in the 4.x line and the only safe starting point. If you are still on 4.3 or earlier, upgrade to 4.4 first using Composer's constraint syntax.

composer require "symfony/symfony:4.4.*" --update-with-all-dependencies

Once on 4.4, run your full test suite with the Symfony deprecation helper enabled. In your .env.test or PHPUnit bootstrap, set SYMFONY_DEPRECATIONS_HELPER=enabled. Every deprecation warning must be treated as a blocking issue. Log them to a file for systematic resolution:

SYMFONY_DEPRECATIONS_HELPER=log-to-file=var/log/deprecations.log vendor/bin/phpunit

Audit your third-party dependencies aggressively. Many bundles pinned to Symfony 4-era versions have no upgrade path. Use composer outdated --direct to identify packages needing updates, and check each bundle's repository for Symfony 5/6/7 compatibility tags. Replace abandoned bundles now; finding replacements mid-migration causes costly context switching. For database-heavy applications, review your MySQL performance tuning configuration before upgrading, as ORM changes in newer Symfony versions may alter query patterns.

Establish a rollback-safe workflow

  • Create a dedicated Git branch per major version (e.g., upgrade/symfony-5, upgrade/symfony-6).
  • Tag your last known-good state on the current version before each upgrade attempt.
  • Ensure CI runs the full test suite plus deprecation checks on every push to upgrade branches.
  • Maintain a staging environment that mirrors production infrastructure, including PHP version and extensions.

What are the critical steps when migrating from Symfony 4 to Symfony 5?

The 4→5 transition is typically the most labor-intensive because it introduces the new Flex-based directory structure as the default and removes many legacy bridges. Your primary tool here is the Symfony CLI's check:requirements command and Composer's interactive update.

symfony check:requirements
composer update "symfony/*" --with-all-dependencies

Symfony 5 requires PHP 7.4 minimum, but target PHP 8.0 or 8.1 if possible to reduce future friction. Update your composer.json platform requirement explicitly:

"config": {
    "platform": {
        "php": "8.0.30"
    }
}

The biggest structural change is the removal of the Symfony\Bundle\FrameworkBundle\Controller\Controller base class. All controllers must extend AbstractController instead. This is usually a simple find-and-replace, but verify that you are not relying on removed methods like $this->get() for service location. Inject dependencies via constructor or method injection instead.

composer update"symfony/*"--with-all-depsFlex Recipe Diffconfig/packages/*.yamlpublic/index.phpAccept ChangesMerge new configReject / ManualPreserve customizationsRun Tests +Deprecation Check
Flex recipe update flow: always review diffs manually when custom configurations exist to avoid overwriting environment-specific settings

Handle Flex recipe conflicts deliberately

When Composer updates Symfony packages, Flex will propose changes to configuration files. Never blindly accept all changes. Review each diff, especially for config/packages/security.yaml, config/services.yaml, and public/index.php. Custom environment variables, security firewalls, and service definitions are frequently overwritten. Use git diff after accepting to verify nothing critical was lost, and keep a reference copy of your pre-upgrade config directory.

How does the Symfony 5 to Symfony 6 upgrade differ from previous migrations?

Symfony 6 drops PHP 7 support entirely and requires PHP 8.0 minimum (8.1+ recommended). This is where type declarations become mandatory in many framework interfaces. If your codebase lacks return types on controller methods, event subscribers, or voter implementations, PHP will throw fatal errors during container compilation.

Add return types systematically. The Rector tool automates this for Symfony-specific interfaces:

composer require rector/rector --dev
vendor/bin/rector process src/ --config=rector.php

Configure Rector with the Symfony 6.0 set in rector.php:

use Rector\Symfony\Set\SymfonySetList;
return static function (RectorConfig $config): void {
    $config->sets([SymfonySetList::SYMFONY_60]);
};

The service container also changed significantly. Autowiring aliases for removed services were deleted, and some previously auto-registered services now require explicit definition. Run bin/console debug:container after upgrading to verify all injected services resolve correctly. Pay special attention to LoggerInterface and CacheItemPoolInterface aliases, which commonly break.

Update testing infrastructure

PHPUnit 9.x is required for Symfony 6. Migrate your phpunit.xml.dist to the new schema, replace deprecated assertion methods, and update test case base classes. BrowserKit and DomCrawler assertions changed signatures; consult the official UPGRADE-6.0.md file for the complete list. Integration tests often reveal hidden service wiring issues that unit tests miss, so prioritize running your full functional suite early.

What final adjustments are needed when completing the migration to Symfony 7?

Symfony 7 requires PHP 8.2 minimum and represents the cleanest state of the framework. Most work here involves removing remaining BC layers and adopting new defaults. The #[Route] attribute replaces annotation-based routing entirely—if you still use DocBlock annotations, convert them now. Native PHP attributes are faster and eliminate the doctrine/annotations dependency.

// Before (annotations)
/** @Route("/api/users", name="api_users") */

// After (attributes)
#[Route('/api/users', name: 'api_users')]

Review the latest PHP features relevant to Symfony 7, including readonly classes, enum improvements, and fiber enhancements. Symfony 7 leverages these extensively internally, and aligning your application code improves both performance and maintainability.

AspectSymfony 6.4 LTSSymfony 7.x
Minimum PHP8.18.2
RoutingAnnotations + AttributesAttributes only
Service IDsFQCN + aliasesFQCN preferred
Deprecation PolicyBC layer retainedBC layer removed
LTS SupportUntil Nov 2026No (next LTS is 7.4)
Bundle CompatibilityWide ecosystemModernized bundles only
Full Test SuiteUnit + Functional + E2E✓ Zero failuresDeprecation ScanSYMFONY_DEPRECATIONS_HELPER✓ Zero warningsPerformance BaselineResponse time + memory✓ Within SLA targetsSecurity Auditcomposer audit + SAST✓ No critical CVEsStaging DeployMirror prod infra✓ Smoke tests passProduction ReleaseBlue-green or canary deployMonitor error rates for 24h post-release
Post-migration verification pipeline: complete all gates before promoting Symfony 7 to production traffic

Validate observability and compliance posture

Framework upgrades can silently alter log formats, trace propagation headers, and metric cardinality. Verify your structured logging configuration still parses correctly and that distributed traces connect across updated middleware. If your organization maintains SOC 2 or ISO 27001 compliance, document the migration as a change control event with evidence of testing, security scanning, and approval. Automated evidence collection in CI makes this straightforward; manual documentation after the fact is error-prone and audit-risky.

Ready to Modernize Your Symfony Application?

Migrating a Symfony 4 app to Symfony 7 is achievable when approached as a series of controlled, reversible steps rather than a monolithic rewrite. Each major version boundary is a checkpoint: resolve deprecations, validate tests, update infrastructure, then proceed. The reward is a modern, secure, performant application aligned with current PHP capabilities and long-term framework support. If your team needs hands-on guidance for complex migrations, legacy bundle replacements, or compliance-integrated upgrade workflows, reach out to discuss your specific situation.

Frequently Asked Questions

No. You must upgrade sequentially through Symfony 5 and 6 first. Skipping major versions breaks dependency resolution and prevents automated Rector refactoring rules from applying correctly during the migration process.

PHP 8.2 minimum.

Run bin/console lint:container after each minor upgrade. Fix all deprecation notices before proceeding to the next major version, as Symfony 7 removes all features deprecated in Symfony 6 without backward compatibility layers.

No. Symfony 7 requires Doctrine ORM 3.x. You must migrate your entity mappings, repositories, and query builders to comply with Doctrine 3 strict typing and removed legacy features before upgrading the framework.

Removed entirely.

Use Rector with the SymfonyLevelSetList::UP_TO_SYMFONY_60 set. This automatically converts route annotations to PHP 8 attributes across controllers, which is mandatory since Symfony 7 drops annotation reader support completely.

Yes. Flex remains the official package manager for managing recipes, environment variables, and bundle configuration. Ensure your flex endpoint is updated and run composer recipes:update after each major version bump to apply new recipe changes.

Refactor bundle classes to extend AbstractBundle instead of Bundle. Move configuration processing to the configure method using the new Configurator API, and replace compiler passes with attribute-based service autoconfiguration where possible for cleaner integration.

PHPUnit 10 or higher is required. Update test configurations to use the new attributes instead of annotations, migrate data providers to static methods, and ensure WebTestCase uses the updated kernel booting mechanism introduced in Symfony 6.4.

Yes. The enable_authenticator_manager option is removed as it is now always enabled. Custom authenticators must implement the new AuthenticatorInterface, and firewall configurations require explicit access_control ordering due to stricter matching logic enforcement.

Two to six weeks depending on codebase size, test coverage, and third-party bundle compatibility. Budget extra time for Doctrine ORM 3 migration and replacing unmaintained packages that lack Symfony 7 support in 2026.

Symfony Mailer.

Achieve zero deprecations on Symfony 6.4 LTS first. Run php bin/console about to confirm version, execute full test suites, validate container compilation, and audit all third-party dependencies for Symfony 7 compatibility tags on Packagist.

Rector automates syntax and API changes but cannot handle architectural decisions or business logic updates. Use it for sequential upgrades between majors, then manually review generated code, fix edge cases, and update tests accordingly.

Missing type declarations on autowired services, removed private service access, and invalid argument types in YAML/XML configs. Enable strict_types in all PHP files and run container linting frequently to catch these issues early.