Skip to main content
Health probes live in the nestrs-health workspace member, modeled on the three-probe shape Kubernetes (and @nestjs/terminus) popularized: liveness (am I running?), readiness (can I serve traffic?), startup (have I finished booting?). Each probe is an HTTP endpoint that returns 200 when its indicators all check out, 503 when any one fails. Results are cached for 5s with in-flight coalescing so a probe storm from an orchestrator doesn’t run every check N times in parallel.

Mount the three probes

install_probes mounts three endpoints at the server root, unaffected by set_global_prefix or URI versioning:
  • GET /__nestrs/health/live — liveness
  • GET /__nestrs/health/ready — readiness
  • GET /__nestrs/health/startup — startup
Pick the subset you want via ProbeKind::all() (liveness + readiness + startup), ProbeKind::live_and_ready(), or pass them individually. Each probe runs only its own indicator set — liveness doesn’t include the database check, readiness does.

Built-in indicators

  • DatabaseIndicator — runs the shared nestrs_core::DatabasePing capability (sqlx / Prisma / Mongo). One line, works across every adapter the framework exposes.
  • HttpIndicator (feature http) — GET a URL, must be 2xx, bounded by a timeout. Use for third-party dependencies where a hand-rolled ping isn’t worth maintaining.
  • DiskSpaceIndicator (feature disk) — statvfs threshold in bytes. Unix-only; the probe reports the feature as missing on Windows rather than crashing.
Indicators that need a connection (database, broker) build with a constructor, not a builder — there’s no connection string to thread through, the indicator pulls the live connection from the DI container at probe time.

Custom indicators

Anything that can be checked asynchronously implements HealthIndicator:
A failure message is the on-call engineer’s first debugging hook — make it specific (the actual depth, the threshold crossed, the resource that didn’t open) rather than “down”.

Broker health for microservices

RedisBrokerHealth issues a PING/PONG round-trip; NatsBrokerHealth opens a TCP connection. Both are bounded — a stuck broker doesn’t hang the probe forever. BrokerHealthStub (always up) is the default in projects that haven’t wired a real broker yet.

How the cache works

Every probe result is cached for 5 seconds. If a probe arrives while a check is in flight, the second caller attaches to the first check rather than starting a parallel one — tokio::sync::OnceCell under the hood. Net effect:
  • A single in-flight check per probe kind, even under burst load.
  • After 5s, the next request triggers a fresh check.
  • Failures don’t stick — if the database recovers within the TTL window, the next probe sees Up immediately.
The TTL is the right knob to tune if your orchestrator probes faster than the indicators can run (down to ~50ms is safe).

When to use what

  • DatabaseIndicator — almost every readiness probe needs this. One line, real signal.
  • HttpIndicator — sparingly. Each one is an outbound dependency you now own failures for. Better: define a narrow contract, check the in-process client, not the upstream.
  • DiskSpaceIndicator — disk pressure kills writes silently. Cheap to add.
  • Custom HealthIndicator — any state you can summarize async: queue depth, replica lag, last successful batch timestamp.

See also