You are inheriting a Symfony application: a contractor left, a developer moved on, or the tool has been running for years and nobody dares to touch it. Before adding a single feature, a short audit stops you from discovering the problems in production.
This article gives the checklist I use, the commands to run and the questions to ask. It complements the broader article on taking over an existing web project and its technical debt.
In short
A Symfony application audit before a takeover checks six things: the Symfony and PHP versions, the state of dependencies, the presence of tests, where the business logic lives, data quality and how the application is deployed. It produces a ranked list of risks and a recommendation: stabilise, upgrade, take over progressively or rebuild one part.
- Version: an application on a Symfony or PHP version that no longer receives security fixes is the first risk to address.
- Dependencies:
composer auditlists known vulnerabilities in seconds. - Tests: without tests on critical user journeys, every change is a gamble.
- Business logic: it is the most expensive part to rebuild, so locate it first.
- Deliverable: a risk map and an action plan, not a list of 200 style remarks.
Why audit a Symfony application before taking it over?
Because a takeover without an audit pays for its surprises at the most expensive moment. The developer finds an outdated version, a hidden business rule or a manual deployment halfway through a change the client asked for. The audit moves these discoveries before the quote and before the first change.
Symfony helps a lot here. The framework is structured: routes, services, entities, forms and commands each have an expected place. A project that follows these conventions reads quickly. A project that works around them is just as easy to spot, and that is already useful information for estimating the takeover.
Which Symfony and PHP versions does the application run on?
The bin/console about command answers in one go: it shows the Symfony version, its end-of-maintenance and end-of-life dates, the PHP version and the environment. It is the first command to run, before even opening the code.
The key date is the end of security fixes. An application exposed to the internet should not run on a version that no longer receives them. Here is the status of each version on 8 October 2026, according to Symfony’s official release calendar:
| Symfony version | Bug fixes until | Security fixes until | What it means for a takeover |
|---|---|---|---|
| 4.4 and earlier | Ended | Ended | Priority upgrade, often in several steps |
| 5.4 (LTS) | November 2024 | February 2029 | Security covered, but no more bug fixes |
| 6.4 (LTS) | November 2026 | November 2027 | Plan the move to 7.4 within the year |
| 7.4 (LTS) | November 2028 | November 2029 | Stable base for a calm takeover |
| 8.1 | January 2027 | January 2027 | Recent version, to follow from release to release |
Intermediate versions missing from this table (5.0 to 5.3, 6.0 to 6.3, 7.0 to 7.3, 8.0) are no longer maintained. On the PHP side, 8.1 and earlier no longer receive security fixes. PHP 8.2 receives them until 31 December 2026, PHP 8.3 until 31 December 2027 and PHP 8.4 until 31 December 2028.
An old version does not force a rewrite. It calls for an upgrade plan, costed and ordered. Moving from one LTS to the next starts by fixing the deprecations reported by the current version.
Are the dependencies up to date and free of known vulnerabilities?
Three Composer commands give the state of dependencies: composer audit for published security advisories, composer outdated --direct for packages that are behind, and composer validate for consistency between composer.json and composer.lock. They take seconds and change nothing.
Then look at what the tools do not tell you:
- packages abandoned by their author, with no version compatible with the next Symfony release;
- forked or vendored bundles copied into the repository, which will never update automatically;
- JavaScript dependencies (
package.json,importmap.php), which often age faster than the PHP side; - deprecations, visible with
bin/console debug:container --deprecationsand in the profiler’s dedicated tab.
The number of deprecations is a good indicator of the cost of the next upgrade. A few dozen can be handled in a few days. Several hundred spread across the code mean a project that needs to be split into stages.
Can you change the code without breaking everything?
Yes if critical user journeys are covered by automated tests, no otherwise. The question is not the overall coverage rate. It is whether login, creating a record, calculating an amount or the export the client relies on are checked on every change.
To find out, run php bin/phpunit and note whether the suite passes, how long it takes and what it actually tests. A suite that has been failing for months is information in itself. If there are no tests, the audit names which journeys to cover first with WebTestCase functional tests, before any change.
Three read-only commands complete this check: bin/console lint:container for service configuration, bin/console lint:twig templates/ for templates and bin/console doctrine:schema:validate to check that the Doctrine mapping matches the database. A static analysis tool such as PHPStan, run at a moderate level, then surfaces type errors and dead code.
Where does the business logic live?
In a healthy Symfony application, business rules live in dedicated services called by short controllers. In an application that aged quickly, they are scattered: in controllers, in Twig templates, in Doctrine listeners, in commands run by cron or directly in SQL.
Locating this logic is the most valuable step of the audit, because it is the most expensive part to rebuild if it gets lost. A few pointers:
bin/console debug:routerlists every route: the hardest ones to read often reveal overloaded controllers;- the most frequently changed files are the risk zones, visible with
git log --format= --name-only | sort | uniq -c | sort -rn | head -20; - scheduled tasks (crontab, Scheduler, Messenger) often carry rules nobody documented;
- current users know the exceptions the code handles silently: a thirty-minute interview is sometimes worth a day of reading.
How is the application deployed, backed up and monitored?
An application you cannot redeploy cannot be taken over safely. The audit must establish how code reaches production, whether a staging environment exists, where secrets are stored and whether database backups have ever been restored at least once.
Points to check:
- is deployment scripted (Deployer, Docker, CI) or done by hand over FTP?
- are Doctrine migrations up to date (
bin/console doctrine:migrations:status), or was the database changed directly? - are secrets in
.env.localor the Symfony secrets vault, or committed to the repository? - are production logs read, and does an error trigger an alert?
How long does an audit take and what should it deliver?
A few days are enough for a modest application with full access to the code, a copy of the database and a test environment. An application with many modules, third-party integrations and dense business logic needs more. The duration is set after a first conversation about scope and available access.
The deliverable should help you decide, not impress you. It contains:
- the context, critical use cases and the scope actually reviewed;
- the state of the foundation: versions, dependencies, architecture;
- the findings, with what was observed and what remains to be checked;
- risks ranked by their impact on users;
- an action plan and the takeover options.
The web application technical audit page describes this engagement in detail.
Example: moving from Symfony 5.4 to 6.4 on a live application
On Schneider Electric’s Circular Certified project, the returns management platform was built on Symfony 5.4, then moved to Symfony 6.4 while it was in use. It generates PDFs and DHL labels and exchanges data with other components through a secured API.
This kind of migration is prepared with exactly the points above: fix the deprecations reported by 5.4, check that every bundle has a compatible version, secure critical journeys with tests, then deploy after acceptance testing. The challenge was not technical novelty but continuity for the teams handling returns every day.
FAQ
Should you upgrade Symfony before resuming development?
Not always before, but always in the plan. If the version no longer receives security fixes, the upgrade comes first. If it is still supported, urgent changes can ship first and the upgrade can be scheduled right after.
Can you audit an application without production access?
Yes, as long as you have the source code, an anonymised copy of the database and a way to run the application. Without production access, the audit simply states what could not be checked, such as real-world performance or server configuration.
Does a code audit replace a penetration test?
No. A code review spots weaknesses within an agreed scope, but does not guarantee the absence of vulnerabilities. A penetration test needs its own framework and specific skills.
Take over or rebuild: who decides?
The client, based on the audit’s findings. The audit’s job is to make the decision readable: the cost of an upgrade, the risks of a rewrite, and the parts that can be kept as they are.
Conclusion
Auditing a Symfony application before taking it over means answering a few simple questions with tools the framework already provides: which version, which vulnerabilities, which tests, where the business rules are, how it is deployed. Most commands listed here change nothing and can be run on day one.
The expected outcome is a reasoned decision, not a verdict. If you are taking over a Symfony application that nobody dares to change any more, describe the situation: we start by reading what exists.
Sources: support calendar published on symfony.com/releases and supported versions on php.net, checked on 8 October 2026.