Avoiding common Laravel anti-patterns
Concept
Deployment and production checklist covers everything needed to go from development to a production-ready Laravel application. Many configuration decisions that are fine locally will cause issues or security problems in production.
Environment configuration:
APP_ENV=production,APP_DEBUG=false.APP_KEYmust be set (used for encryption). Generate withphp artisan key:generate.- Use environment-specific
.envfiles, not committed to git. - Use
.env.exampleas the template.
Performance caching (run on every deploy):
php artisan config:cache # merge all config files
php artisan route:cache # compile route definitions
php artisan view:cache # pre-compile Blade views
php artisan event:cache # cache event/listener map
composer install --optimize-autoloader --no-dev
php artisan optimize # runs the above togetherDatabase:
php artisan migrate --force(required flag in production).- Test migrations on staging before running on production.
- Backup before running migrations.
Queue workers: Run php artisan queue:work as a long-running process via Supervisor or a platform service. Configure retries, timeouts, failed job handling.
Horizon (if used): php artisan horizon managed by Supervisor.
Scheduled tasks: Add the single cron entry that runs php artisan schedule:run every minute.
Health checks: A /health endpoint that checks DB connectivity, cache, queue, and returns 200 or 500.
Zero-downtime deploy: Atomic deploys (Forge, Vapor, Deployer), maintenance mode (php artisan down/up), run migrations after code deploy.
Code Example
# Example deploy script (Deployer or CI/CD)
# 1. Switch to maintenance mode
php artisan down --retry=60 --secret="bypass-token"
# 2. Update code
git pull origin main
# 3. Install dependencies (no dev, optimized autoloader)
composer install --no-dev --optimize-autoloader
# 4. Run migrations
php artisan migrate --force
# 5. Clear and rebuild caches
php artisan optimize:clear # clear all caches
php artisan optimize # rebuild all caches
# 6. Restart queue workers (so they pick up new code)
php artisan queue:restart
# 7. Bring back online
php artisan up<?php
// Health check endpoint
// routes/web.php
Route::get('/health', function() {
$checks = [
'database' => fn() => \Illuminate\Support\Facades\DB::connection()->getPdo() && true,
'cache' => fn() => \Illuminate\Support\Facades\Cache::set('health', true, 10) && true,
'storage' => fn() => is_writable(storage_path()),
];
$results = [];
$healthy = true;
foreach ($checks as $name => $check) {
try {
$results[$name] = $check() ? 'ok' : 'fail';
} catch (\Throwable $e) {
$results[$name] = 'fail: ' . $e->getMessage();
$healthy = false;
}
}
return response()->json([
'status' => $healthy ? 'healthy' : 'unhealthy',
'checks' => $results,
'version' => config('app.version', 'unknown'),
], $healthy ? 200 : 500);
})->name('health');
// Supervisor config for queue worker
// [program:laravel-queue]
// command=php /var/www/artisan queue:work redis --sleep=3 --tries=3 --timeout=90
// autostart=true
// autorestart=true
// numprocs=2
// redirect_stderr=true
// stdout_logfile=/var/www/storage/logs/worker.log