Back to Blog
Zero-Downtime Deployments for Laravel Applications
Users Shouldn't Notice Deployments
Every minute of downtime costs money and trust. Zero-downtime deployment ensures users experience uninterrupted service during updates.
The Release Directory Pattern
/var/www/
├── releases/
│ ├── 20241012-001/
│ ├── 20241012-002/
│ └── 20241012-003/ # Current
├── current -> releases/20241012-003/
├── storage/ # Shared
└── .env # Shared
Deployment Script
#!/bin/bash
set -e
RELEASE=$(date +%Y%m%d-%H%M%S)
RELEASES_DIR=/var/www/releases
CURRENT_DIR=/var/www/current
SHARED_DIR=/var/www/shared
# Clone repository
git clone --depth 1 $REPO $RELEASES_DIR/$RELEASE
cd $RELEASES_DIR/$RELEASE
# Install dependencies
composer install --no-dev --optimize-autoloader
# Link shared resources
ln -s $SHARED_DIR/.env .env
ln -s $SHARED_DIR/storage storage
rm -rf public/storage
ln -s $SHARED_DIR/storage/app/public public/storage
# Build assets
npm ci && npm run build
# Run migrations
php artisan migrate --force
# Optimize
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Atomic symlink switch
ln -sfn $RELEASES_DIR/$RELEASE $CURRENT_DIR
# Reload PHP-FPM
sudo systemctl reload php8.3-fpm
# Restart queue workers
php artisan queue:restart
# Cleanup old releases (keep 5)
ls -dt $RELEASES_DIR/*/ | tail -n +6 | xargs rm -rf
Using Envoy
// Envoy.blade.php
@servers(['web' => 'deploy@example.com'])
@setup
$repo = 'git@github.com:user/repo.git';
$release = date('YmdHis');
$releases = '/var/www/releases';
$current = '/var/www/current';
@endsetup
@task('deploy')
git clone --depth 1 {{ $repo }} {{ $releases }}/{{ $release }}
cd {{ $releases }}/{{ $release }}
composer install --no-dev
php artisan migrate --force
ln -sfn {{ $releases }}/{{ $release }} {{ $current }}
sudo systemctl reload php8.3-fpm
@endtask
// Run with: envoy run deploy
Database Migrations
For zero-downtime, migrations must be backward compatible:
- Add columns as nullable first
- Deploy code that handles both states
- Backfill data
- Add constraints in subsequent deployment
Conclusion
Zero-downtime deployment requires the release directory pattern, atomic symlink switches, and careful migration strategies. The complexity is worth the user experience improvement.
Related Articles
Need Help With Your Project?
I respond to all inquiries within 24 hours. Let's discuss how I can help build your production-ready system.
Get In Touch