Learn to implement atomic deployments using symlink switches in your CI/CD pipeline, ensuring your Laravel SaaS remains available during every release.
Previously in this course, we explored High-Availability Infrastructure to ensure our services stay online despite localized failures. Today, we focus on the deployment process itself: how to push new code to production without dropping a single request.
In a standard git pull or rsync deployment, your files are updated in place. If a request hits your server while the files are mid-copy, the application may enter an inconsistent state, leading to 500 errors or missing assets. To achieve true zero-downtime, we must decouple the deployment of files from the activation of the release.
The core concept of an atomic deployment is that the switch between the "old" code and the "new" code must be instantaneous. We achieve this using a symlink-based directory structure.
Instead of deploying directly to a single public_html folder, we create a structure where the web server points to a symlink. When a new version is ready, we update the symlink to point to the new folder in a single, atomic filesystem operation.
TEXT/var/www/my-saas/ ├── current -> /var/www/my-saas/releases/20231027120000 ├── releases/ │ ├── 20231027100000/ │ └── 20231027120000/ └── shared/ ├── .env └── storage/
releases/: Contains timestamped directories of every deployment.shared/: Holds files that persist across deployments, such as storage/ and the .env file.current/: A symlink that your Nginx/Apache root points to.The deployment pipeline follows these steps:
releases/.composer install, npm install) and run build tasks inside the new directory.shared/ directories/files into the new release directory.current symlink.Here is a simplified Bash implementation of the atomic switch:
Bash# 1. Generate timestamp RELEASE_DIR="/var/www/my-saas/releases/$(date +%Y%m%d%H%M%S)" # 2. Deploy to new directory git clone --depth 1 git@github.com:org/repo.git $RELEASE_DIR # 3. Link shared assets ln -nfs /var/www/my-saas/shared/.env $RELEASE_DIR/.env ln -nfs /var/www/my-saas/shared/storage $RELEASE_DIR/storage # 4. Run build steps cd $RELEASE_DIR composer install --no-dev --optimize-autoloader php artisan migrate --force php artisan view:cache # 5. Atomic symlink switch ln -nfs $RELEASE_DIR /var/www/my-saas/current
The ln -nfs command is the secret sauce. By using the -n (no-dereference) and -f (force) flags, the symlink update happens as an atomic system call. The web server process will resolve the path to the old release until the exact millisecond the link is updated, at which point it begins resolving to the new one.
For our SaaS platform, we are moving away from manual scripts. We are now integrating this logic into our CI/CD pipeline using GitHub Actions. If you’ve followed our previous work on Zero-downtime deploy with GitHub Actions, you can now replace the simple copy steps with this symlink strategy.
An atomic deployment strategy leaves behind old code folders, which will eventually fill your disk. Create a simple cleanup script to run after your deployment:
Bash# Keep only the last 5 releases cd /var/www/my-saas/releases && ls -dt */ | tail -n +6 | xargs rm -rf
Add this to your deployment pipeline to ensure disk space remains managed.
php artisan queue:restart immediately after the switch to ensure they pick up the new code.Atomic deployments leverage symlinks to swap out application versions instantly. By separating the build process from the activation process, you eliminate the risk of serving partially-updated code to your users. Combine this with additive database migrations and Redis-backed state to ensure your Laravel SaaS remains rock-solid during deployments.
Up next: We will dive into Advanced OAuth2 Implementation to secure our multi-tenant SaaS architecture.
Master production-grade asset management in Laravel. Learn to implement file hashing for versioning and configure Vite to scale your frontend performance via CDN.
Read moreMaster SQL indexing for joins by learning to analyze execution plans and build covering indexes that eliminate table scans in high-traffic Laravel applications.
Zero-Downtime Deployment Pipelines
Custom Middleware Development
Database Connection Pooling
Handling Large Data Exports
Security Header Configuration
Database Sharding Concepts
Real-time Data Synchronization
Database Deadlock Prevention
Managing Third-Party API Integrations