Looking to hire Laravel developers? Try LaraJobs

laravel-healthcheck maintained by philiprehberger

Description
Configurable health check endpoint with built-in checks and Kubernetes probe support
Last update
2026/04/06 18:37 (dev-main)
License
Downloads
42

Comments
comments powered by Disqus

Laravel Healthcheck

Tests Latest Version on Packagist License

Configurable health check endpoint with built-in checks and Kubernetes probe support.

Features

  • Drop-in health check endpoint at /health (configurable prefix)
  • Kubernetes liveness (/health/live) and readiness (/health/ready) probes
  • Built-in checks: database, cache, storage, Redis, queue, environment, HTTP
  • Pluggable: implement HealthCheck to add your own checks
  • Per-check timeout with graceful critical fallback
  • Optional result caching to reduce backend load
  • Configurable middleware and route prefix
  • Full test suite, PHPStan level 8, Laravel Pint enforced

Requirements

  • PHP ^8.2
  • Laravel ^11.0 or ^12.0

Installation

composer require philiprehberger/laravel-healthcheck

Laravel's package auto-discovery registers the service provider automatically.

Publishing the config

php artisan vendor:publish --tag=healthcheck-config

This creates config/healthcheck.php.

Usage

Basic health check

Once installed, the following endpoints are immediately available:

Endpoint Description
GET /health Full report — 200 if healthy, 503 if not
GET /health/live Liveness probe — always 200
GET /health/ready Readiness probe — 200 if healthy, 503 if not

Example response from GET /health:

{
  "status": "ok",
  "duration_ms": 14.52,
  "checks": [
    {
      "name": "database",
      "status": "ok",
      "message": "Database connection is healthy.",
      "meta": { "connection": "mysql" }
    },
    {
      "name": "cache",
      "status": "ok",
      "message": "Cache is healthy.",
      "meta": []
    },
    {
      "name": "environment",
      "status": "ok",
      "message": "Environment configuration looks healthy.",
      "meta": { "env": "production", "debug": false }
    }
  ]
}

When any check is critical or warning, the overall status reflects that and the HTTP status code becomes 503.

Status levels

Level Meaning
ok Check passed
warning Non-fatal issue (e.g. debug enabled)
critical Check failed — affects readiness

The overall report status is critical if any check is critical; warning if any is warning and none is critical; ok only if all checks are ok.

Configuration

config/healthcheck.php:

return [
    'route_prefix' => env('HEALTHCHECK_ROUTE_PREFIX', 'health'),

    'middleware' => [],

    'checks' => [
        \PhilipRehberger\Healthcheck\Checks\DatabaseCheck::class,
        \PhilipRehberger\Healthcheck\Checks\CacheCheck::class,
        \PhilipRehberger\Healthcheck\Checks\StorageCheck::class,
        \PhilipRehberger\Healthcheck\Checks\EnvironmentCheck::class,
    ],

    'timeout' => (int) env('HEALTHCHECK_TIMEOUT', 5),

    'cache' => [
        'enabled' => (bool) env('HEALTHCHECK_CACHE_ENABLED', false),
        'ttl'     => (int) env('HEALTHCHECK_CACHE_TTL', 30),
    ],
];

Restricting access with middleware

'middleware' => ['auth:sanctum'],

Or use a custom IP-allowlist middleware for infrastructure-only access.

Enabling result caching

To avoid hammering your database on every probe poll:

HEALTHCHECK_CACHE_ENABLED=true
HEALTHCHECK_CACHE_TTL=30

Built-in checks

DatabaseCheck

Tests that a PDO connection can be established.

new DatabaseCheck()                    // uses default connection
new DatabaseCheck('mysql_reporting')   // named connection

CacheCheck

Writes, reads, and deletes a probe key using the default cache driver. Resource cleanup is guaranteed — the probe key is always removed via try-finally, even if cache operations fail.

StorageCheck

Writes, reads, and deletes a probe file on the default filesystem disk. Resource cleanup is guaranteed — the probe file is always deleted via try-finally, even if read or content verification fails.

new StorageCheck()        // default disk
new StorageCheck('s3')    // named disk

RedisCheck

Calls PING on the Redis connection. Returns a warning (not critical) if the Redis extension and Predis are both absent so the check degrades gracefully in environments without Redis.

new RedisCheck()             // default connection
new RedisCheck('cache')      // named connection

QueueCheck

Resolves the queue connection from the container to verify connectivity.

new QueueCheck()             // default connection
new QueueCheck('redis')      // named connection

EnvironmentCheck

Returns a warning when APP_DEBUG=true in a production environment.

HttpCheck

Pings an external URL and verifies the response status code.

new HttpCheck('https://api.stripe.com')
new HttpCheck('https://api.stripe.com', timeout: 3, expectedStatus: 200, checkName: 'stripe')

Register via the service container for constructor-injected checks:

// AppServiceProvider::register()
$this->app->bind(\PhilipRehberger\Healthcheck\Checks\HttpCheck::class, fn () =>
    new \PhilipRehberger\Healthcheck\Checks\HttpCheck(
        url: 'https://api.stripe.com',
        checkName: 'stripe_api',
    )
);

Then add the class string to config/healthcheck.php checks array.

Writing custom checks

Implement the HealthCheck contract:

use PhilipRehberger\Healthcheck\CheckResult;
use PhilipRehberger\Healthcheck\Contracts\HealthCheck;

class ElasticsearchCheck implements HealthCheck
{
    public function name(): string
    {
        return 'elasticsearch';
    }

    public function check(): CheckResult
    {
        try {
            $info = app('elasticsearch')->info();

            return CheckResult::ok(
                $this->name(),
                'Elasticsearch is healthy.',
                ['version' => $info['version']['number']],
            );
        } catch (\Throwable $e) {
            return CheckResult::critical($this->name(), $e->getMessage());
        }
    }
}

Register in config/healthcheck.php:

'checks' => [
    // ...
    ElasticsearchCheck::class,
],

Kubernetes probe configuration

Deployment manifest

livenessProbe:
  httpGet:
    path: /health/live
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 15
  failureThreshold: 3

readinessProbe:
  httpGet:
    path: /health/ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 2

Liveness (/health/live) — always returns 200 as long as PHP-FPM/Octane is alive. Kubernetes will restart the container only if this stops responding, not on application-level failures.

Readiness (/health/ready) — returns 200 only when all health checks pass. Kubernetes removes the pod from load balancer rotation while this returns 503, enabling zero-downtime deploys during database migrations or cold-start delays.

Ingress — skip auth middleware on probe endpoints

If you add auth middleware globally, exclude the probe paths in your ingress or use a separate middleware group:

// config/healthcheck.php
'route_prefix' => 'health',
'middleware'   => [],   // no auth on probes — protect at the network level instead

API

HealthCheck (Interface)

Method Return Type Description
name(): string string Unique check identifier
check(): CheckResult CheckResult Execute the check and return a result

CheckResult

Method Description
CheckResult::ok(string $name, string $message, array $meta) Passing result
CheckResult::warning(string $name, string $message, array $meta) Non-fatal warning
CheckResult::critical(string $name, string $message, array $meta) Failing result

Development

composer install
vendor/bin/phpunit
vendor/bin/pint --test
vendor/bin/phpstan analyse

License

MIT