0

Avoiding common Laravel anti-patterns

Advanced5 min read·lv-27-008
interview

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_KEY must be set (used for encryption). Generate with php artisan key:generate.
  • Use environment-specific .env files, not committed to git.
  • Use .env.example as the template.

Performance caching (run on every deploy):

bash
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 together

Database:

  • 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

bash
# 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
<?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