DEV Community

Cover image for Zero-Downtime Deployments in Laravel
Prajapati Paresh
Prajapati Paresh

Posted on Originally published at smarttechdevs.in

Zero-Downtime Deployments in Laravel

The Unacceptable Cost of Maintenance Mode

In the early days of a startup, deploying new code to a Laravel application is a relatively stress-free event. You SSH into your production server, pull the latest Git branch, run composer install, run your database migrations, and perhaps restart the PHP-FPM process. To prevent users from seeing fatal errors during this 30-second window, you run php artisan down, putting the application into Maintenance Mode.

However, when you scale into an enterprise B2B SaaS platform processing thousands of transactions a minute, a 30-second maintenance window is no longer a minor inconvenience—it is a catastrophic breach of your Service Level Agreement (SLA). If a deployment takes place during a critical business hour, active API integrations will fail, user uploads will drop, and revenue will be actively lost. Furthermore, if the deployment contains a critical bug, rolling back requires another maintenance window, compounding the downtime.

At Smart Tech Devs, we engineer platforms that require 99.99% uptime. To achieve this, we completely eradicate the concept of "Maintenance Mode" by architecting Zero-Downtime Deployments utilizing the Blue/Green Deployment Architecture.

The Philosophy of Blue/Green Architecture

The core concept of Blue/Green deployment is that you maintain two identical production environments. Let's call the currently active environment "Blue". It is handling 100% of the live user traffic. The "Green" environment is entirely idle and hidden from the public internet.

When you are ready to deploy a new feature, you do not touch the Blue environment. Instead, you deploy the new code to the Green environment. You install composer dependencies, compile frontend assets, and run caching commands entirely in the background. Once the Green environment is fully built and passes automated health checks, you flip a switch at the Load Balancer (or Nginx layer) to instantly route all new traffic to Green. Green becomes the new active environment, and Blue becomes the idle backup.

Phase 1: The Infrastructure Layer (Symlink Routing)

While massive enterprises might use dedicated Kubernetes clusters to achieve this, you can architect a highly effective Blue/Green system on a single server or a smaller cluster using Symlink Swapping. Tools like Laravel Envoy or Deployer natively support this.

Instead of serving your application from /var/www/html, you serve it from a symlink: /var/www/current. This symlink points to a specific release folder, timestamped at the moment of deployment.


# Server Directory Structure
/var/www/
├── releases/
│   ├── 20240501100000/ (Previous Release - Idle)
│   ├── 20240515120000/ (Active Release - Blue)
│   └── 20240520140000/ (Building Release - Green)
├── shared/
│   ├── .env
│   └── storage/
└── current -> /var/www/releases/20240515120000/

When the Green release (20240520140000) is finished building, the deployment script executes a single, atomic Linux command to swap the symlink:


ln -sfn /var/www/releases/20240520140000 /var/www/current
sudo service php8.2-fpm reload

Because the symlink update is atomic, there is zero downtime. The very next HTTP request that hits Nginx instantly executes the new code.

Phase 2: The Database Migration Crisis

Flipping a symlink solves the codebase problem, but it introduces a terrifying database problem. The Blue environment and the Green environment share the same physical database. If you run a Laravel migration that drops a column (e.g., ALTER TABLE users DROP COLUMN phone_number) while the Blue environment is still active and relying on that column, you will instantly crash the live application before the symlink even flips.

To architect Zero-Downtime Deployments, you must fundamentally change how you write database migrations. Migrations must be backwards compatible. You can no longer perform destructive database changes in a single deployment.

The Phased Database Migration Strategy

If you need to rename a column from phone_number to mobile_number, you must do it across three separate, isolated deployments:

  1. Deployment 1 (Expand): Create a migration that adds the new mobile_number column. Do not drop the old column. Update your Laravel code to write data to both columns simultaneously to keep them in sync.
  2. Deployment 2 (Migrate): Write a background job to backfill the data from the old column into the new column for historical rows. Update your Laravel code to now exclusively read and write from the new mobile_number column.
  3. Deployment 3 (Contract): Weeks later, once you are mathematically certain that no code in your application relies on the old column, you create a migration to finally DROP COLUMN phone_number.

This phased expansion and contraction guarantees that your database schema remains valid for both the currently running Blue release and the newly building Green release, neutralizing the risk of migration-induced downtime.

Phase 3: Managing Shared State (Cache and Sessions)

In a Blue/Green architecture, your storage directory must be decoupled from the release folders. If users upload profile pictures, those pictures cannot live inside the release directory, or they will vanish when the symlink flips.

This is why your storage/app/public folder must be a symlink to a centralized /var/www/shared/storage folder. Furthermore, your application state (Sessions, Cache, and Queues) must be entirely decoupled from the file system. You must configure your .env to utilize Redis for all state management.


# Shared .env Configuration
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

When the symlink flips, active user sessions remain perfectly intact in Redis, and background queue workers seamlessly transition to processing jobs using the new codebase without losing a single payload.

The Engineering ROI and Instant Rollbacks

Implementing Blue/Green Deployments and Symlink Swapping fundamentally alters the psychology of an engineering team. Deployments cease to be high-stress events that require midnight maintenance windows; they become boring, routine operations that can be executed at 2:00 PM on a Tuesday.

The ultimate architectural benefit is the Instant Rollback. If the Green environment goes live and your telemetry detects a spike in 500 errors, you do not need to run a reverse deployment. You simply execute one command to revert the symlink back to the Blue folder. Within one millisecond, your application is restored to the exact, stable state it was in prior to the deployment, preserving your enterprise SLAs and protecting your revenue streams.

Top comments (0)