javidev / laravel-health-check
Artisan command that checks DB, cache, queue and storage, and prints a clean console report.
Requires
- php: ^8.1
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/console: ^10.0|^11.0|^12.0
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/filesystem: ^10.0|^11.0|^12.0
- illuminate/queue: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-07-27 20:05:14 UTC
README
Know if your Laravel app is actually healthy — in one Artisan command.
Database down? Redis unreachable? S3 failing writes? Queue stuck?
Stop guessing. Run app:health and get a clear, timed report in seconds.
php artisan app:health
Health Check
+----------+--------+----------------------------------------+--------+
| Service | Status | Detail | Time |
+----------+--------+----------------------------------------+--------+
| Database | ✔ OK | Connection OK (mysql) | 4.2 ms |
| Cache | ✔ OK | Write/read OK (driver: redis) | 1.1 ms |
| Queue | ✔ OK | Connection 'redis' OK (0 pending jobs) | 2.8 ms |
| Storage | ✔ OK | Write/read OK (disk: s3) | 89 ms |
+----------+--------+----------------------------------------+--------+
All good (4/4)
Requires PHP 8.1+ and Laravel 10+.
Why this package?
Production incidents rarely start in your controllers. They start when MySQL refuses connections, Redis dies, S3 times out, or the queue connection breaks.
This package gives you a battle-ready way to:
| Without this package | With laravel-health-check |
|---|---|
| SSH in and poke each service manually | One command, one report |
| Write ad-hoc scripts per project | Install once, reuse everywhere |
| Guess what failed in CI / Docker | Exit code 1 when something is broken |
| Build custom JSON for monitors | --json out of the box |
Built for developers who ship Laravel apps and want zero-friction observability at the infrastructure layer.
Features
- One command —
php artisan app:healthchecks DB, cache, queue & storage - Beautiful console output — status, detail message, and duration per check
- JSON mode — pipe into uptime tools, dashboards, or HTTP endpoints
- Fail-fast for CI & containers —
--fail-on-errorexits1on any failure - Zero extra config — uses your existing Laravel
database,cache,queue, andfilesystemsconfig - Safe by default — probe keys/files are always cleaned up (
try/finally) - Fluent API —
DatabaseCheck::new()->connection('mysql') - Programmatic runner — inject
HealthCheckeranywhere in your app - Extensible — write custom checks in ~15 lines with
AbstractCheck - Production-grade internals —
finalclasses, enums,hrtimetiming, PHPStan level 6, Pint, CI
Table of contents
- Installation
- Usage
- Configuration
- Available checks
- Programmatic usage
- Custom checks
- Scheduling
- CI / Docker / Kubernetes
- Architecture
- Testing
- Changelog
- Contributing
- Security
- Credits
- License
Installation
Install via Composer:
composer require javidev/laravel-health-check
Laravel auto-discovers the service provider. No manual registration required.
Publish the config (optional)
php artisan vendor:publish --tag=health-check-config
This publishes config/health-check.php so you can enable, disable, or reorder checks.
Local / path development
Developing the package locally? Add a path repository to your app's composer.json:
{
"repositories": [
{
"type": "path",
"url": "../laravel-health-check"
}
],
"require": {
"javidev/laravel-health-check": "*"
}
}
composer update javidev/laravel-health-check
Usage
Console report
php artisan app:health
Runs every registered check and prints a table with service name, status, detail, and duration in milliseconds.
JSON output
Perfect for uptime monitors, external dashboards, or your own /health endpoint:
php artisan app:health --json
[
{
"name": "Database",
"ok": true,
"status": "ok",
"message": "Connection OK (mysql)",
"duration_ms": 4.21
},
{
"name": "Cache",
"ok": true,
"status": "ok",
"message": "Write/read OK (driver: redis)",
"duration_ms": 1.08
}
]
Fail on error
Exit with code 1 when any check fails — ideal for CI pipelines, cron jobs, and container healthchecks:
php artisan app:health --fail-on-error
| Situation | Exit code |
|---|---|
| All checks pass | 0 |
| One or more fail | 1 |
Without --fail-on-error, the command always exits 0 so you can still inspect the report.
Configuration
// config/health-check.php return [ 'checks' => [ \JaviDev\HealthCheck\Checks\DatabaseCheck::class, \JaviDev\HealthCheck\Checks\CacheCheck::class, \JaviDev\HealthCheck\Checks\QueueCheck::class, \JaviDev\HealthCheck\Checks\StorageCheck::class, ], ];
Remove what you don't need. Add your own checks that extend AbstractCheck (or implement HealthCheck).
Available checks
| Check | What it does | Fluent options |
|---|---|---|
| Database | Opens a connection and runs select 1 |
->connection('mysql') |
| Cache | Writes, reads, and deletes a probe key | ->store('redis') |
| Queue | Resolves the connection and reports pending jobs | ->connection('redis') |
| Storage | Writes, reads, and deletes a probe file | ->disk('s3') |
All checks respect your existing Laravel configuration (database.default, cache.default, queue.default, filesystems.default).
Probe keys and files are always cleaned up, even when a check fails mid-way.
Programmatic usage
Use the same engine outside Artisan — controllers, jobs, Octane, whatever you need:
use JaviDev\HealthCheck\HealthChecker; use JaviDev\HealthCheck\Checks\DatabaseCheck; use JaviDev\HealthCheck\Checks\CacheCheck; $report = app(HealthChecker::class)->run([ DatabaseCheck::new()->connection('mysql'), CacheCheck::new()->store('redis'), ]); if (! $report->ok()) { logger()->critical('Health check failed', $report->toArray()); // notify Slack, abort deploy, etc. } return response()->json($report->toArray());
Custom checks
Extend AbstractCheck — timing and exception handling are handled for you:
<?php declare(strict_types=1); namespace App\HealthChecks; use Illuminate\Support\Facades\Http; use JaviDev\HealthCheck\Checks\AbstractCheck; use JaviDev\HealthCheck\Checks\HealthCheckResult; final class MeilisearchCheck extends AbstractCheck { public function name(): string { return 'Meilisearch'; } protected function check(): HealthCheckResult { $response = Http::timeout(3) ->get(config('scout.meilisearch.host').'/health'); if (! $response->successful()) { return $this->fail('Unexpected status: '.$response->status()); } return $this->pass('Cluster is healthy'); } }
Register it:
'checks' => [ \JaviDev\HealthCheck\Checks\DatabaseCheck::class, \App\HealthChecks\MeilisearchCheck::class, ],
Scheduling
Keep an eye on production every few minutes.
Laravel 11+ (routes/console.php):
use Illuminate\Support\Facades\Schedule; Schedule::command('app:health --fail-on-error')->everyFiveMinutes();
Laravel 10 (app/Console/Kernel.php):
protected function schedule(Schedule $schedule): void { $schedule->command('app:health --fail-on-error')->everyFiveMinutes(); }
CI / Docker / Kubernetes
GitHub Actions
- name: Application health check run: php artisan app:health --fail-on-error
Dockerfile
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD php artisan app:health --fail-on-error || exit 1
Docker Compose
healthcheck: test: ["CMD", "php", "artisan", "app:health", "--fail-on-error"] interval: 30s timeout: 5s retries: 3
Architecture
Clean separation of concerns — the command never owns business logic:
app:health (Command) ← presentation only
└── HealthChecker ← resolves & runs checks
└── HealthCheckReport
└── HealthCheckResult[]
└── CheckStatus (enum)
| Piece | Responsibility |
|---|---|
| Command | Table / JSON / exit codes |
| HealthChecker | Orchestration + validation |
| AbstractCheck | Shared hrtime timing + safety net |
| Checks | One job each — final, fluent, focused |
Testing
composer test # PHPUnit composer lint # Laravel Pint composer analyse # PHPStan level 6 composer check # all of the above
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details. Pull requests are welcome.
Security Vulnerabilities
If you discover a security-related issue, please open a private GitHub security advisory instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.