Zero-Downtime Deploys for Laravel, Explained Simply

Zero-Downtime Deploys for Laravel, Explained Simply

21 October 2026 · By Laravel Git · 2 min read

The naive Laravel deploy is git pull on the live directory, and it has a window where the code is half-old, half-new - composer autoloads one version, the templates reference another, and a visitor in that second gets a broken page. Zero-downtime deploys remove the window with one idea: never change the directory the web server is looking at.

The structure, used by every deploy tool worth using:

/var/www/app/
  releases/
    20261020-141122/
    20261021-093015/
  current -> releases/20261021-093015
  shared/
    .env
    storage/

Each deploy is a full checkout into a new timestamped directory. Composer install, artisan config:cache, asset builds - all happen there, while current still points at the previous release and the site keeps serving it. The switch is a single atomic operation: repoint the current symlink. If anything is wrong, point it back - rollback takes one second because the old release directory is still intact.

Two things must live outside releases: .env and storage/. Symlink them in from shared/ so every release uses the same environment and the same uploaded files.

Migrations are the hard part#

Code swaps are easy; databases cannot be symlinked back. The rule that keeps deploys reversible: every migration must work with both the old and the new code. Adding a column is fine. Renaming one is not - do it as three deploys (add new, backfill and dual-write, drop old). Run php artisan migrate --force before the symlink swap, so the schema is ready for the release that is about to go live.

The queue and scheduler#

Laravel queues hold serialized jobs, so after the swap, restart the workers (artisan queue:restart) or they keep running the old code from memory. The scheduler needs no restart - cron resolves through current on each run.

That is the whole shape: build beside, switch atomically, migrate compatibly, restart workers. Whether you script it yourself or adopt a tool, Deploy Laravel With Git Push covers the pipeline around it, and Deploy With Tags, Not Branches decides what each release directory should contain. A deploy your users never notice is not luxury - it is just structure.

Share this post

Our network