Laravel is a joy to build with. It's also very good at failing quietly. Most production incidents we see on Laravel apps aren't dramatic crashes — they're jobs that stopped processing three days ago, or a setting that silently became null. Here are the ones that come up again and again.

Queue workers running old code

Queue workers are long-running processes. They load your code once and keep it in memory. Deploy new code without restarting them, and they carry on happily running the old version.

Add php artisan queue:restart to every deploy. It tells workers to finish their current job and exit, and your process manager (Supervisor, systemd or Horizon) starts fresh ones.

env() returns null after config:cache

php artisan config:cache is great for performance. But once the config is cached, the .env file is no longer loaded — so any call to env() outside your config/ files returns null.

The rule is simple: only call env() inside config files, and everywhere else use config('services.stripe.key'). Search your codebase for env( outside config/ today; it takes five minutes.

The scheduler that never runs

Laravel's scheduler depends on one cron entry calling php artisan schedule:run every minute. On a new server, a new container setup or a migration to Kubernetes, that entry is easy to forget. Nothing errors — your nightly reports just stop.

Monitor scheduled tasks with a heartbeat: have each important task ping an uptime service when it completes, and alert if the ping doesn't arrive.

File sessions behind a load balancer

The default file session driver stores sessions on the local disk. Add a second server behind a load balancer and users start getting logged out at random, because each request may land on a server that has never heard of them. Use Redis or the database for sessions and cache as soon as you have more than one instance.

N+1 queries that appear with real data

A page that runs 12 queries with test data can run 1,200 with production data. Add this to AppServiceProvider in development:

Model::preventLazyLoading(! app()->isProduction());

It turns accidental lazy loading into an exception you'll notice immediately, instead of a slow page you'll notice months later.

OPcache left on defaults

Make sure OPcache is enabled in production, with enough memory for your codebase. If you deploy by replacing the code directory, either reload PHP-FPM after deploying or use a symlinked release directory, so OPcache doesn't serve stale files.

The pattern behind all of these

None of these problems are bugs in Laravel. They're operational details that live outside the application code, which is exactly why they're forgotten. Write them into your deploy script and your runbook once, and they stop being surprises.