or press Ctrl + P

Symfony Production Readiness Checklist

Use this checklist to verify that your Symfony application is configured correctly for a production environment.

Performance

OPcache

OPcache caches your code as compiled bytecode, so PHP doesn't have to reinterpret it on every request. It ships with PHP by default since 8.5; on older versions the extension sometimes has to be installed first. Check the following values, for example through phpinfo() or in php.ini (see Runtime Configuration for all options):

  • OPcache is enabled (opcache.enable = 1)

  • OPcache preloading is enabled (opcache.preload holds the full path to Symfony's config/preload.php)

    Preloading compiles the listed files once at server startup and keeps them in shared memory for every worker, so the framework's core classes never have to be loaded from disk per request.

  • opcache.preload_user is set to the web server user (usually www-data)

  • opcache.memory_consumption is 256 or higher

  • opcache.max_accelerated_files is 32531 or higher

  • OPcache is not checking PHP files for changes on every request (opcache.validate_timestamps = 0)

    With timestamp validation off, OPcache skips a filesystem stat() on every cached file per request. The tradeoff is that it no longer notices changed files, so the cache has to be cleared on each deployment (see Deployment below).

realpath cache

PHP resolves relative file paths to absolute ones and caches the result in the realpath cache. Check that it is sized generously:

  • realpath_cache_size is 4096K or higher
  • realpath_cache_ttl is 600 seconds (10 minutes) or longer

Xdebug

  • The Xdebug extension is absent or disabled in production

    Xdebug hooks into the engine and slows down every request, even when no debugging session is active.

Application configuration

Symfony configuration

Check the following values, usually in config/:

  • framework.enabled_locales (usually in config/packages/translation.yaml) lists only the locales the application actually uses
  • .container.dumper.inline_factories: true set as a parameter in config/services.yaml

Doctrine configuration

If Doctrine ORM is used, also check the following, usually in config/packages/doctrine.yaml (see also Caching Drivers):

  • doctrine.dbal.server_version (or the serverVersion parameter in the DATABASE_URL environment variable) set to the database version running in production

    Without it, DBAL runs a query to detect the version on the first connection of every request. Setting it also lets Doctrine pick the right SQL dialect for your database.

  • The query cache is configured (doctrine.orm.query_cache_driver)

  • The result cache is configured (doctrine.orm.result_cache_driver)

Deployment

Build and release

Check the application's build and deployment process (see also Performance):

  • The application uses an optimized class map (composer dump-autoload --no-dev --classmap-authoritative)

    An authoritative class map lets the autoloader resolve every class from a precomputed array, so it never falls back to searching the filesystem (and won't look for a class that isn't there).

  • OPcache is cleared after every deployment (for example by restarting the web server), so it picks up the changed files

    Needed because production OPcache runs with validate_timestamps = 0, so it won't notice the new files on its own.

Security

Dependencies and versions

Server and access

  • The web server user (usually www-data) can only read the application's source files, not modify them

  • The public directory contains no files with sensitive information (such as a .env)

  • The load balancer / proxy IP addresses are configured through the SYMFONY_TRUSTED_PROXIES environment variable or framework.trusted_proxies (usually in config/packages/framework.yaml)

    Only relevant behind a load balancer or reverse proxy (such as an ingress controller in Kubernetes). Without it, Symfony treats the proxy as the client and ignores the X-Forwarded-* headers, so the client IP, scheme and host are wrong. See How to Configure Symfony to Work behind a Load Balancer or a Reverse Proxy.

Public-facing

User experience

  • Custom error pages are set for HTTP status codes such as 404, 403 and 500 (usually in templates/bundles/TwigBundle/Exception/)

    The default Symfony error page looks broken to visitors. A custom template keeps the experience on-brand even when something goes wrong (see How to Customize Error Pages).

  • A custom favicon is set

Search engine optimization

  • The site has a robots.txt file in the public directory
  • Symfony generates an XML sitemap that can be submitted to search engines, for example with PrestaSitemapBundle