Symfony upgrade
Skill krzysztofsurdy/code-virtuoso/skills/frameworks/symfony/symfony-upgrade
Symfony framework version upgrade guide using the deprecation-first approach. Use when the user asks to upgrade Symfony to a new minor or major version, fix deprecation warnings, update Symfony recipes, check bundle compatibility, migrate between LTS versions, or plan a Symfony version migration strategy. Covers PHPUnit Bridge deprecation tracking, recipe updates, bundle compatibility checks, version-specific breaking changes, and the changelog-first upgrade workflow.From its SKILL.md
npx -y skills add krzysztofsurdy/code-virtuoso --skill symfony-upgradeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 20 stars20 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 8 commands, including `composer update "symfony/*"` and 7 more.
- fetches URLsInstructs the agent to fetch 1 URL, including https://github.com/symfony/symfony/blob/X.Y/UPGRADE-X.Y.md.
SKILL.md
9.0 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it
Symfony Framework Upgrade
Symfony's upgrade model is built on one core insight: a new major version is identical to the last minor version of the previous branch, minus deprecated code. Fix all deprecations first, then the major upgrade is trivial.
Core Principles
| Principle | Meaning |
|---|---|
| Changelog first | Before any upgrade, search the web for the actual UPGRADE-X.Y.md file or ask the user for the changelog - never rely on static knowledge alone |
| Deprecation-first | Fix every deprecation on the current version before upgrading to the next major - Symfony 8.0 is 7.4 minus deprecations |
| Incremental minor upgrades | Upgrade 6.2 -> 6.3 -> 6.4, never skip minors - each surfaces new deprecations |
| Recipes keep config current | Run composer recipes:update after every upgrade to sync configuration files |
| Test deprecation count | Use SYMFONY_DEPRECATIONS_HELPER to fail builds when direct deprecations appear |
| Update bundles first | Third-party bundles are the most common blocker - update them before bumping Symfony |
Critical First Step: Read the Changelog
Before touching any code or running any command, you MUST obtain the actual changelog for the target version:
- Search the web for
Symfony UPGRADE-X.Y.md(e.g.,Symfony UPGRADE-7.0.md github) - Or ask the user to provide the changelog / release notes
- Read the UPGRADE file in the Symfony repository:
https://github.com/symfony/symfony/blob/X.Y/UPGRADE-X.Y.md - Check the Symfony blog for the release announcement with highlighted changes
This is non-negotiable. Each version has unique changes that static skill knowledge cannot fully capture. The changelog tells you exactly what broke, what was deprecated, and what was removed.
Symfony Release Model
| Release Type | Cycle | Support | Example |
|---|---|---|---|
| Patch (X.Y.Z) | Monthly | Bug fixes only | 7.4.1 -> 7.4.2 |
| Minor (X.Y) | Every 6 months (May + November) | May add deprecations, no BC breaks | 7.3 -> 7.4 |
| Major (X.0) | Every 2 years (November, odd years) | Removes deprecated code, may have BC breaks | 7.x -> 8.0 |
| LTS (X.4) | Always the X.4 release | 3 years bug fixes, 4 years security fixes | 6.4 LTS, 7.4 LTS |
Each major branch has exactly 5 minor versions: X.0, X.1, X.2, X.3, X.4 (LTS).
Minor Version Upgrade (e.g., 7.3 -> 7.4)
Step 1: Read the Changelog
Search the web for UPGRADE-7.4.md in the Symfony repository. Identify new deprecations and any changes that affect your code.
Step 2: Update composer.json
With Symfony Flex (recommended):
{
"extra": {
"symfony": {
"require": "7.4.*"
}
}
}
Without Flex, update each symfony/* constraint manually.
Step 3: Run Composer Update
composer update "symfony/*"
If dependency conflicts arise:
composer update "symfony/*" --with-all-dependencies
Step 4: Update Recipes
composer recipes:update
Step 5: Run Tests
vendor/bin/phpunit
Major Version Upgrade (e.g., 6.4 -> 7.0)
Phase 1: Read the Changelog
Search the web for UPGRADE-7.0.md in the Symfony repository. This file lists every backward-compatibility break and every removed deprecation. Read it completely before starting.
Phase 2: Eliminate All Deprecations
This is the bulk of the work. Do this while still on the current major version.
A. Detect deprecations via tests:
composer require --dev symfony/phpunit-bridge
Configure strict deprecation handling in phpunit.xml.dist:
<php>
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[direct]=0"/>
</php>
Run tests and fix every direct deprecation:
vendor/bin/phpunit
B. Detect deprecations in browser:
Visit the app in dev environment, check the Symfony Profiler's deprecation panel in the web debug toolbar.
C. Automate fixes with Rector:
composer require --dev rector/rector rector/rector-symfony
// rector.php
use Rector\Config\RectorConfig;
use Rector\Symfony\Set\SymfonySetList;
return RectorConfig::configure()
->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
->withSets([SymfonySetList::SYMFONY_70]);
vendor/bin/rector process --dry-run
vendor/bin/rector process
D. Handle indirect deprecations:
Indirect deprecations come from third-party bundles. Update them to versions that support the target Symfony version:
composer outdated
composer update vendor/bundle-name
Phase 3: Bump Symfony Version
With Flex:
{
"extra": {
"symfony": {
"require": "7.0.*"
}
}
}
composer update "symfony/*" --with-all-dependencies
rm -rf var/cache/*
Note: packages like symfony/polyfill-*, symfony/ux-*, and some symfony/*-bundle follow their own versioning - do not force them to the new major.
Phase 4: Update Recipes
composer recipes # list all, see which have updates
composer recipes:update # interactive update, one at a time
The command generates a diff between your installed recipe version and the latest, applies it as a git patch. Resolve conflicts like normal git conflicts. Commit your work before running this.
Phase 5: Test Thoroughly
vendor/bin/phpunit
vendor/bin/phpstan analyse
Deploy to staging before production.
See Upgrade Workflow Reference for detailed deprecation handling, SYMFONY_DEPRECATIONS_HELPER options, and bundle compatibility strategies.
SYMFONY_DEPRECATIONS_HELPER Options
| Configuration | Effect |
|---|---|
max[direct]=0 | Fail on any deprecation caused by your code |
max[indirect]=999 | Tolerate deprecations from vendor code during transition |
max[total]=0 | Fail on any deprecation from any source (strictest) |
disabled=1 | Disable deprecation tracking entirely (not recommended) |
generateBaseline=true&baselineFile=./tests/allowed.json | Snapshot current deprecations to a baseline file |
baselineFile=./tests/allowed.json | Ignore deprecations already in the baseline (ratchet approach) |
Handling Third-Party Bundles
Bundles are the most common upgrade blocker. Follow this order:
- Check compatibility - look at each bundle's
composer.jsonfor Symfony version constraints - Update bundles first -
composer updatebefore bumping Symfony version - Check for forks - if a bundle is abandoned, look for maintained forks on Packagist
- Wrap risky dependencies - use adapter pattern to isolate bundles that may not keep up
For bundle maintainers, use feature detection instead of version checks:
// Bad - version-based check
if (Kernel::VERSION_ID <= 60400) { ... }
// Good - feature-based check
if (!method_exists(OptionsResolver::class, 'setDefined')) { ... }
Support multiple versions with flexible constraints:
{
"require": {
"symfony/framework-bundle": "^6.4|^7.0"
}
}
Quick Reference: Major Upgrade Checklist
- Search the web for
UPGRADE-X.0.mdand read it completely - Upgrade to the last minor of current major (e.g., 6.4)
- Update all third-party bundles to latest versions
- Configure
SYMFONY_DEPRECATIONS_HELPERwithmax[direct]=0 - Run test suite and fix all direct deprecations
- Run Rector with Symfony deprecation rules
- Verify zero direct deprecations in test output
- Update
extra.symfony.requireto new major version - Run
composer update "symfony/*" --with-all-dependencies - Clear cache:
rm -rf var/cache/* - Run
composer recipes:updateuntil all recipes are current - Run full test suite
- Run static analysis
- Deploy to staging and verify
- Deploy to production and monitor logs
Reference Files
| Reference | Contents |
|---|---|
| Upgrade Workflow | Detailed deprecation handling workflow, recipes:update deep dive, CI pipeline integration, and version-specific migration notes |
Integration with Other Skills
| Situation | Recommended Skill |
|---|---|
| Upgrading PHP version alongside Symfony | Use the php-upgrade playbook skill |
| Updating Composer dependencies | Use the composer-dependencies playbook skill |
| Working with Symfony components | Use the symfony-components skill in frameworks/symfony/ |
| Modernizing PHP code patterns | Install php-modernization from dirnbauer/webconsulting-skills |
What ships with it: 1 file
6.6 KB alongside SKILL.md
references/
- upgrade-workflow.md6.6 KB
Gives 1 of the 12 instructions most migration upgrade skills give in ~2.2k tokens
Counted across 48 of the 65 authors here whose files we hold, read 2026-09-06
- Install @total-typescript/shoehornin 8 of 48
- Replace `as unknown as Type` with `fromAny()`in 8 of 48
- Replace `as Type` with `fromPartial()`in 8 of 48
- Find test files with `as` assertions using grepin 8 of 48
- Run the type check to verify the migrationin 7 of 48
- Import helpers from @total-typescript/shoehornin 6 of 48
- Use `fromExact()` to force complete objectsin 6 of 48
- Ask the user which test files have problematic `as` assertionsin 5 of 48
- Upgrade one minor version at a timehere, and in 4 of 48, across 3 files
- Upgrade the SDK before upgrading the Qdrant serverin 4 of 48, across 3 files
- Perform a rolling upgrade one node at a timein 4 of 48, across 3 files
- Use `fromAny()` for intentionally wrong test datain 4 of 48
Said here and by no other author read
- Fix all deprecations before upgrading the major version
- Update third-party bundles before bumping the framework version
- Run recipes:update after every upgrade
- Configure the deprecation helper to fail on direct deprecations
- Run the test suite and fix all direct deprecations
- Use Rector to automate deprecation fixes
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.