Maintenance mode isn’t built into Symfony out of the box, but you can easily add it using community bundles or by writing a simple custom solution. Below are the methods to implement maintenance mode for Symfony 6.4 (or above), plus recommendations and best practices.

1. Using a Maintenance Bundle

One of the most common and reliable ways is to use a bundle that handles maintenance mode for you.

a) ToshY / Lexik Maintenance Bundle

  • Package: toshy/maintenance-bundle packagist.org

  • Installation:

     
    composer require toshy/maintenance-bundle
  • Features:

    • Enable/disable maintenance via console commands (maintenance:enable, maintenance:disable). packagist.org

    • Return a 503 Service Unavailable status code while in maintenance. packagist.org

    • Whitelist IPs: you can configure certain IP addresses to bypass the maintenance mode and still access the site. packagist.org

    • Storage options: supports file-based lock, database, or even memcache. packagist.org

  • Configuration example (YAML):

     
    # config/packages/maintenance_mode.yaml maintenance_mode: enabled: true # or false allowed_ips: [ '127.0.0.1', 'YOUR.IP.ADDRESS' ] lock_file_path: '%kernel.cache_dir%/maintenance.lock'

b) Kefisu Maintenance Bundle

  • Package: kefisu/maintenance-bundle packagist.org

  • Installation:

     
    composer require kefisu/maintenance-bundle
  • Features:

    • Simple file-based storage of the maintenance state (default in cache or tmp). packagist.org

    • Enable / disable via CLI. packagist.org

    • Customizable response page (you can define how users see the maintenance page). packagist.org

  • Configuration example:

     
    # config/packages/maintenance.yaml maintenance: maintenance_file_path: '%kernel.cache_dir%/maintenance'

c) Drawik Maintenance Mode Bundle

  • Package: drawik/symfony-maintenance-mode-bundle packagist.org

  • Installation:

     
    composer require drawik/symfony-maintenance-mode-bundle
  • Usage commands:

     
    bin/console maintenance:enable bin/console maintenance:disable
  • Configuration options:

d) FreezLike Maintenance Bundle

  • Package: freezlike/maintenance-bundle packagist.org

  • Features:

    • Activate/deactivate maintenance mode. packagist.org

    • Option to set a “next maintenance date,” so users know when the site will be back. packagist.org

    • Role-based bypass: allow certain roles (e.g., ROLE_ADMIN) to access the site even during maintenance. packagist.org

  • Configuration:

     
    # config/packages/maintenance.yaml maintenance: active: false next_maintenance_date: '2025-12-31 12:30' allowed_role: 'ROLE_ADMIN'

2. Custom Approach (Without a Bundle)

If you don’t want to use a third-party bundle, you can build a basic maintenance mode yourself:

  1. Use Kernel Event Subscriber

    • Create an event subscriber on kernel.request.

    • Check for a “maintenance” flag. This could be an environment variable, a file in cache, or a database entry.

    • If maintenance is enabled and the request is not from an allowed IP / user, return a Symfony Response with status 503 and a custom maintenance page.

     
    // src/EventSubscriber/MaintenanceSubscriber.php namespace App\EventSubscriber; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class MaintenanceSubscriber implements EventSubscriberInterface { private string $lockFile; private array $allowedIps; public function __construct(string $lockFile, array $allowedIps = []) { $this->lockFile = $lockFile; $this->allowedIps = $allowedIps; } public static function getSubscribedEvents(): array { return [ RequestEvent::class => 'onKernelRequest', ]; } public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); $clientIp = $request->getClientIp(); if (file_exists($this->lockFile) && !in_array($clientIp, $this->allowedIps, true)) { // Option A: Throw 503 throw new HttpException(503, 'Service unavailable: maintenance in progress.'); // Option B: Return a custom Response // $response = new Response('Maintenance in progress', 503); // $event->setResponse($response); } } }
    • Configuration: define the lock file path and allowed IPs in your services.yaml or parameters.yaml.

  2. Enable / Disable Maintenance Mode

    • To turn on maintenance: create the lock file (e.g. touch var/maintenance.flag).

    • To turn off: remove the file (rm var/maintenance.flag).

    • This is a very simple but effective mechanism.

  3. Custom Maintenance Page

    • Create a Twig template (e.g. templates/maintenance.html.twig) for your maintenance page.

    • Use it when returning the 503 Response in your subscriber.

3. Best Practices for Maintenance Mode in Symfony

  • Use 503 Status Code: Always return HTTP 503 (Service Unavailable) during maintenance. It tells clients and search engines that downtime is temporary.

  • Graceful Bypass: Allow certain IPs, roles, or users (admins, devs) to bypass to test things during maintenance.

  • Cache Behavior: Be careful with caching. You don’t want proxies or CDNs to cache your maintenance page forever. Use appropriate headers (Cache-Control: no-store, Retry-After).

  • Automate Maintenance During Deployments: Add maintenance enable/disable commands to your deployment script. For example, run maintenance:enable before deployment and maintenance:disable after.

  • Inform Users: If possible, show a friendly maintenance page with an estimated “back online” time.

  • Health Checks: Even in maintenance mode, health check endpoints (e.g., for load balancers) might need to remain accessible.

Conclusion

For a Symfony 6.4 (or newer) application, using a dedicated maintenance bundle (like ToshY, Kefisu, Drawik, or FreezLike) is the easiest and most reliable way to enable maintenance mode. But if you want full control, implementing a custom subscriber gives you flexibility and avoids third-party dependencies.