
September 09, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
Your Laravel app can pass unit tests and still go down in production without anyone noticing. Laravel Health Checks and Uptime Monitoring close that gap by verifying database, cache, queue, and disk dependencies on a schedule—and paging you when the homepage stops responding. On production deployments I've maintained, a silent queue failure or expired SSL certificate caused more damage than a code bug. The same patterns apply whether you run Nagios-style server checks or Laravel-specific probes. This guide covers built-in Laravel options, Spatie's health package, custom endpoints, and external uptime tools you can wire up tonight.
What Are Laravel Health Checks and Why Do They Matter in Production?
A health check is a lightweight HTTP request that confirms your app and its dependencies are working. Uptime monitoring runs that request from outside your server on a fixed interval. Together they answer two different questions: "Can the app serve traffic right now?" and "Did something break five minutes ago while I was asleep?"
In my experience working on production Laravel applications, teams discover outages from customer complaints far too often. Booking portals, payment callbacks, and document upload workflows fail quietly when Redis dies or a queue worker stops. Health checks turn those silent failures into alerts you can act on before revenue or trust is lost.
Think of monitoring in three layers. Layer one is infrastructure: CPU, disk, and PHP-FPM process count. Layer two is application health: can Laravel connect to MySQL and Redis? Layer three is business flow: can a user complete checkout or upload a document? Most teams stop at layer one and wonder why the site "looks fine" while orders stop processing.
For Laravel 13.x on PHP 8.3 or higher—or Laravel 12 on PHP 8.2—you already have framework support for the second layer. You still need external uptime monitoring for the first signal when nginx misroutes traffic or a deploy leaves opcache serving stale bytecode.
How Do You Set Up the Built-In Laravel /up Health Route?
Laravel 11 and later ship a built-in health endpoint at /up. Laravel 13.x keeps this pattern. The route returns HTTP 200 when the framework boots successfully. It is a smoke test, not a full dependency audit, but it catches fatal errors, misconfigured .env files, and broken autoloaders immediately after deploy.
Confirm the route exists
Check bootstrap/app.php for the health registration:
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->create(); Hit it locally or on staging:
curl -i https://your-app.test/up A healthy response returns 200 OK with a minimal body. Point your uptime monitor here first. It costs nothing and validates that PHP-FPM, the web server, and Laravel bootstrap all work together.
When /up is not enough
The built-in route does not verify MySQL, Redis, or queue workers. I've seen production apps return 200 on /up while every page requiring the database threw 500 errors because credentials rotated but opcache still held old config. Treat /up as a deploy gate, then add deeper checks for anything business-critical. Our Ubuntu server monitoring guide covers the infrastructure layer that complements this endpoint.
How Do You Build Custom Laravel Health Check Endpoints?
A custom endpoint gives you full control over what "healthy" means. Keep it fast, unauthenticated for the monitor IP range if needed, and separate from user-facing routes so traffic spikes do not skew results.
Create a dedicated health controller
Generate a controller and register a route outside heavy middleware:
php artisan make:controller HealthCheckController
Route::get('/health', HealthCheckController::class)
->middleware('throttle:60,1'); Example controller that checks database, cache, and disk:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class HealthCheckController extends Controller
{
public function __invoke()
{
$checks = [
'database' => $this->checkDatabase(),
'cache' => $this->checkCache(),
'disk' => $this->checkDisk(),
];
$healthy = ! in_array(false, $checks, true);
return response()->json([
'status' => $healthy ? 'ok' : 'fail',
'checks' => $checks,
'time' => now()->toIso8601String(),
], $healthy ? 200 : 503);
}
private function checkDatabase(): bool
{
try {
DB::connection()->getPdo();
DB::select('SELECT 1');
return true;
} catch (\Throwable) {
return false;
}
}
private function checkCache(): bool
{
$key = 'health:'.uniqid();
Cache::put($key, '1', 10);
return Cache::get($key) === '1';
}
private function checkDisk(): bool
{
$free = disk_free_space(storage_path());
$total = disk_total_space(storage_path());
return ($free / $total) > 0.05;
}
} Return HTTP 503 when any check fails. Uptime tools treat non-2xx responses as down. Use JSON so you can inspect failures quickly—our JSON formatter helps when you paste monitor logs into tickets.
Protect the endpoint
Public health routes attract scanners. Options that work in practice:
- Restrict by IP at the web server or firewall level.
- Require a shared secret header:
X-Health-Tokenchecked in middleware. - Rate-limit aggressively; monitors need one request per minute, not thousands.
- Never expose stack traces or internal hostnames in the JSON body.
On legal-tech portals and booking systems I've shipped, a failing health check during business hours beats discovering the problem from an angry client email at 10 PM.
Should You Use Spatie Laravel Health or Roll Your Own?
Spatie Laravel Health is the package I reach for when a client wants a dashboard, scheduled checks, and notification hooks without maintaining custom probe code. It runs checks on a schedule via the Laravel scheduler and stores results you can expose on a secured route or Filament widget.
Install with Composer 2.10:
composer require spatie/laravel-health
php artisan vendor:publish --tag="health-config"
php artisan health:install Register checks in a service provider:
use Spatie\Health\Facades\Health;
use Spatie\Health\Checks\Checks\DatabaseCheck;
use Spatie\Health\Checks\Checks\RedisCheck;
use Spatie\Health\Checks\Checks\QueueCheck;
use Spatie\Health\Checks\Checks\UsedDiskSpaceCheck;
Health::checks([
DatabaseCheck::new(),
RedisCheck::new(),
QueueCheck::new(),
UsedDiskSpaceCheck::new()->warnWhenUsedSpaceIsAbovePercentage(80)
->failWhenUsedSpaceIsAbovePercentage(90),
]); Schedule the runner in routes/console.php or your scheduler config:
Schedule::command('health:check')->everyMinute(); Spatie also ships queue and schedule heartbeat checks—critical for Laravel apps where php artisan queue:work runs under Supervisor and the scheduler runs from cron. A common mistake is monitoring only the homepage while jobs pile up unseen.
| Approach | Best for | Pros | Cons |
|---|---|---|---|
Built-in /up | Post-deploy smoke test | Zero config, fast | No dependency checks |
Custom /health | Full control, minimal deps | Tailored probes, simple JSON | You maintain all check logic |
| Spatie Laravel Health | Teams wanting dashboards | Rich checks, notifications, history | Extra package + scheduler load |
| External uptime SaaS | 24/7 external perspective | Global probes, SLA reports | Cannot see internal queue depth alone |
For a modular monolith or API-heavy app, combine Spatie scheduled checks with an external monitor on a public URL. See modern Laravel architecture best practices for how monitoring fits release discipline.
How Do You Monitor Queues, Scheduler, and Background Jobs?
HTTP uptime alone misses the most painful Laravel outages: queue workers that died after deploy and schedulers pointing at a stale release path. I've hit both on Deployer 7 symlink deployments where cron still referenced the previous release directory.
Queue worker heartbeat
Dispatch a lightweight job every minute from the scheduler. Write a timestamp to cache or a heartbeats table. Your health endpoint reads it and fails if the last heartbeat is older than three minutes.
Schedule::job(new QueueHeartbeatJob)->everyMinute();
public function checkQueueHeartbeat(): bool
{
$last = Cache::get('queue:heartbeat');
return $last && now()->diffInMinutes($last) < 3;
} Run workers under Supervisor with autorestart. After each deploy, reload PHP-FPM and restart workers so they pick up new code. Our support and maintenance service includes exactly this kind of post-deploy checklist for production Laravel apps.
Scheduler verification
Laravel's scheduler needs a single cron entry:
* * * * * cd /var/www/app/current && php artisan schedule:run >> /dev/null 2>&1 Spatie's ScheduleCheck verifies the scheduler ran recently. Without it, nightly backups, report emails, and subscription renewals simply stop. On Adventure Third Pole Trek, booking reminders depend on the scheduler—monitoring it is not optional.
Failed job alerts
Wire Laravel's Queue::failing() callback or use Horizon's notification channels if you run Redis queues at scale. Pair this with Laravel notifications beyond email for SMS or Slack when payment or webhook jobs fail repeatedly.
Which External Uptime Monitoring Tools Work Best with Laravel?
Application health endpoints must be polled from outside your server. If the datacenter network fails or nginx misconfigures SSL, an in-server cron job cannot tell you the site is unreachable from Kathmandu or Omaha.
SaaS uptime monitors
Services like UptimeRobot, Better Stack, Pingdom, and StatusCake hit your URL every 1–5 minutes from multiple regions. Configure them to:
- Monitor
https://yourdomain.com/upfor basic availability. - Monitor
https://yourdomain.com/healthand assert JSON contains"status":"ok"where supported. - Set alert thresholds: two consecutive failures before paging, response time warn above 2 seconds.
- Add SSL expiry checks—Let's Encrypt renewals fail silently when port 80 is blocked.
Free tiers cover small business sites. Paid tiers add on-call rotations and status pages. Budget roughly Rs 2,000–5,000/month (~USD 15–37) for a serious multi-site setup.
Self-hosted options
Uptime Kuma and Healthchecks.io run on your own VPS if you prefer not to send probe data to third parties. Pair self-hosted uptime with Prometheus and Grafana when you already export PHP-FPM and MySQL metrics. Our Linux system administration service covers installing and hardening these stacks on Ubuntu 22/24.
What to alert on
Prioritize alerts that map to user pain:
- Homepage and login page HTTP status.
- Custom health JSON returning 503.
- SSL certificate expiry within 14 days.
- Response time sustained above your p95 target.
- Queue heartbeat stale for more than five minutes.
- Disk usage above 90% on the volume holding
storage/and logs.
Use Laravel Telescope only in staging or behind strict auth—not as uptime monitoring. It helps after an alert fires, not before.
For API-first apps, add a lightweight authenticated ping route documented in your OpenAPI spec. See Laravel API best practices and building RESTful APIs with Laravel for versioning and health route conventions that play well with gateways.
Database and Redis deep checks
Slow queries do not always fail health checks. Add optional timing thresholds: if SELECT 1 takes more than 500 ms, return a warning state. For PostgreSQL 18 or MySQL 9.7 backends, connection pool exhaustion shows up as intermittent timeouts first. Cross-read PostgreSQL for Laravel developers and N+1 query detection when response-time alerts fire without hard failures.
Official Laravel deployment guidance recommends verifying application health after each release. The Laravel 13.x deployment documentation covers optimization and the built-in health route in the release workflow context.
Key Takeaways
- Enable Laravel's built-in
/uproute as your first post-deploy smoke test, then add a custom/healthendpoint that returns 503 when dependencies fail. - Monitor queue workers and the scheduler with heartbeat checks—homepage uptime alone hides the failures that hurt eCommerce and booking apps most.
- Use Spatie Laravel Health when you want scheduled checks, disk thresholds, and notification hooks without writing probe code from scratch.
- Point an external uptime service at your health URL from multiple regions; assert JSON status where the tool supports content matching.
- Protect health routes with IP allowlists or secret headers, rate limits, and zero internal detail in public responses.
- Wire alerts to Slack or SMS for failed payment and webhook jobs, not just for HTTP downtime.
People Also Ask
Does Laravel have a built-in health check endpoint?
Yes. Laravel 11 and later register a /up route via bootstrap/app.php. It confirms the framework boots and returns HTTP 200. It does not test database, cache, or queue connectivity—you add those in a custom endpoint or with Spatie Laravel Health.
What HTTP status code should a failed Laravel health check return?
Return 503 Service Unavailable when any critical dependency fails. Uptime monitors treat non-2xx codes as down. Use 200 only when all required checks pass. Optional warnings can stay 200 with a degraded status in JSON if your monitor supports content assertions.
How often should you run Laravel uptime monitoring?
Probe every 1–5 minutes from at least two geographic regions. Business-critical apps warrant one-minute intervals with two-failure confirmation before alerting. Scheduled in-app checks via health:check can run every minute; align external polls similarly without exceeding rate limits.
Can you use Laravel Telescope for uptime monitoring?
No. Telescope is a debugging tool for requests, jobs, and queries in non-production or restricted environments. It does not replace external uptime monitoring or scheduled health checks. Use it to investigate after an alert, not as the alert source itself.
Ship Monitoring Before the Next Outage
Laravel Health Checks and Uptime Monitoring are cheap insurance compared to lost orders, missed booking confirmations, or a law-firm portal that silently stops accepting documents. Start tonight: confirm /up, build a JSON /health route, restart queue workers after deploy, and point an external monitor at both URLs. If you want this wired into your deploy pipeline on Laravel 13.x or need post-incident hardening on an existing app, see our enterprise application development and testing and optimization services—or review how we run production stacks on Quick And Easy Nepalese Grocery. Contact us to audit your current setup and get alerts working before the next silent failure.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

