Handling deprecated routes using Symfony compiler passes

Antonio Turdo
2 min readAug 31, 2023


When we deprecate a route in our application, it can be useful to define tracking logic to run when that route is still being called, for example, to send logs or metrics.

The simplest approach involves defining this logic in a service and invoking it at the beginning of all deprecated actions. However, with this solution, we will need to manage the service dependency in each relevant controller and remember to call it for every new deprecated route.

To trigger the execution of the tracking logic, it could be useful to leverage the construct that documents the route as deprecated.

Documenting deprecated routes

If we use the NelmioApiDocBundle to document our APIs, we just need to add the deprecated property to the PHP attribute that describes the endpoint, as shown in this example:

With similar, easily implementable solutions, it’s possible to use the PHPDoc annotation @deprecated or a PHP attribute defined for this purpose within our application.

Identifying deprecated routes

In a Symfony compiler pass, we can identify all deprecated actions by using the controller.service_arguments tag and PHP reflections. We set the resulting array as a dependency for the listener we will see in the next section.

Compiler passes are executed only during the compilation of the Symfony container, for example, when running the cache:clear command or upon the first request the application responds to.

To activate the execution of the compiler pass, remember to add it to the container by modifying (or adding) the build method in our Kernel, calling the addCompilerPass method of the container builder.

Running the tracking logic

Finally, for each request received by the application, we check if the called action is one of those deprecated and, if so, we run our tracking logic.

Alternatively, we could have utilized reflections directly within the listener, but with the implemented approach the code executed for each request is less demanding.


Using some Symfony’s dependency injection and PHP constructs, we’ve automated the tracking logic to execute upon invoking deprecated routes, merely by documenting them as such.

This way, our code is simpler and cleaner, and we avoid the risk of forgetting to explicitly invoke the logic when we make a new deprecation.