Laravel Production Deployment Checklist (2026)
- 7 min read
Laravel Production Deployment Checklist
Laravel makes local development easy enough that it’s tempting to deploy the same way it runs on your machine. Most production incidents in Laravel apps aren’t framework bugs, they’re a handful of config and infrastructure steps that only matter once real traffic and real data are involved.
Configuration
APP_DEBUG=falsein production, without exception. Debug mode exposes stack traces, environment variables, and file paths to anyone who triggers an error.APP_ENV=productionset correctly, since several packages and Laravel itself change behavior based on this value.- Config cached: run
php artisan config:cacheas part of the deploy step. Without it, Laravel re-reads and re-parses every.envvalue on every request. - Routes and views cached:
php artisan route:cacheandphp artisan view:cachereduce per-request overhead the same way config caching does. - A fresh
APP_KEYgenerated for production, never reused from a local or staging environment. Session and cookie encryption depend on it.
Queues
- A real queue worker process, not
QUEUE_CONNECTION=sync. Sync mode runs jobs inline during the request, which works locally and silently makes every “background” job block the user’s response time in production. - A process monitor (Supervisor, systemd, or your host’s equivalent) keeping queue workers alive and restarting them after deploys. Workers hold the old code in memory until restarted, deploying new code without restarting workers means jobs keep running the previous version indefinitely.
- Failed job handling configured, so a failing job is retried or logged instead of silently disappearing.
Database
- Migrations run as part of deploy, not manually after.
php artisan migrate --force(the--forceflag is required in production since Laravel blocks migrations there by default without it). - Connection pooling considered if traffic is meaningful, a naive connection-per-request pattern under load is a common source of “works fine until it doesn’t.”
- Backups verified, not just scheduled. A backup job that’s been silently failing for weeks is worse than no backup, because it creates false confidence.
Caching and Sessions
- A real cache driver (Redis or Memcached), not the
fileorarraydriver, once there’s more than one server or process involved. File-based caching doesn’t share state across multiple app instances. - Sessions off the
filedriver for the same reason, once you’re behind a load balancer with more than one app server, file-based sessions randomly log users out depending on which server handles a given request.
Error Monitoring
- An error tracking service wired in (Sentry or similar) before launch, not after the first user report of something broken. Laravel’s default logs are fine for debugging locally, they’re not a substitute for real-time alerting in production.
Common Mistakes
- Deploying with
storage/andbootstrap/cache/not writable by the web server user, causing cryptic 500 errors that look unrelated to permissions. - Forgetting to clear the config cache after an
.envchange. Onceconfig:cachehas run, Laravel stops reading.envdirectly, so a changed environment variable silently has no effect until the cache is cleared and rebuilt. - Assuming local
.envvalues carry over. Every environment variable used anywhere in the app needs a deliberate, correct production value, not an inherited default from local development.
None of this is exotic. It’s a short, boring list that’s easy to skip under deadline pressure, and the reason most Laravel production incidents trace back to exactly one of these items being missed.