Skip to main content

Rollup status

Overall HealthResponse.status is computed from all check results for that probe:
  1. Any fail → fail (unless remapped by onFail.treatAs on that check).
  2. Else any degraded → degraded.
  3. Else ok.
Override with rollup.computeStatus(results) for custom rules.

HTTP status

Response status (HTTP code) is derived from the rolled-up health status and your config:
  • Any check with status === "fail" and onFail.httpStatus set → that value is returned (first matching check in config order wins among failed checks with a custom status).
  • Else if rollup is fail: defaults.onFail.httpStatus or 503.
  • Else if rollup is degraded: the first check in config order with status === "degraded" and onDegraded.httpStatus set wins. If none matches, use defaults.onDegraded.httpStatus or 200. A degraded override never takes precedence over a failed rollup.
  • Else 200.
onFail.treatAs changes the check status before HTTP mapping. A failure remapped to "degraded" uses onDegraded.httpStatus or degraded defaults, not onFail.httpStatus. Custom rollups to "ok" or "fail" do not use degraded overrides.

Output

output on the root config:
  • format: "json" (default) or "text".
    • JSON: Content-Type: application/json, full output serializes HealthResponse after applying exposure controls.
    • Text: Content-Type: text/plain, human-readable lines (status:, then each check with latency and optional error).
  • exposeError: Default true. If false, the error field is omitted from each check in the payload.
  • exposeMetadata: Default true, preserving all adapter metadata in JSON. Set false to omit metadata, or pass a readonly array of JSON Pointer paths such as ["/region", "/service/version"] to include only those scalar leaves. An empty array omits metadata. Text output never includes metadata.
  • detail: "full" (default) or "status". Status-only JSON is exactly {"status":"ok"} (or "degraded" / "fail"); text is exactly status: ok. It omits timestamps, check names, latency, cache details, errors, and metadata, regardless of other exposure settings.
Every health response includes Cache-Control: no-store, for successful and failing checks. Fetch helpers preserve this header, including on HEAD responses with no body. Your framework integration should forward all response headers.

Public endpoints

Use status-only output for endpoints exposed outside your trusted network:
If you need per-check status and timing, use detail: "full" with exposeError: false and exposeMetadata: false. Check names remain visible in full output. To expose selected metadata, use exposeMetadata: ["/region", "/service/version"] and review those values for sensitive content. Allowlists use exact JSON Pointer paths, with ~1 for / and ~0 for ~ in a key. Only own data properties of plain objects are traversed, and only strings, booleans, null, and finite numbers are copied. Selecting /service does not include an object or its children; select /service/version explicitly. Arrays (including their elements), accessors, class instances, inherited properties, and non-JSON values are excluded. Invalid or missing paths and paths containing __proto__, prototype, constructor, or toJSON segments are ignored. There are no wildcards. This prevents a newly added nested secret or custom serializer from being included through an allowed parent. These controls filter only serialized HTTP output in both formats. Check execution, scheduler caches, internal structured diagnostics, custom rollup inputs, and HTTP status selection retain full diagnostics. Observability integrations should use internal results before output filtering. HealthResponse continues to describe the full internal response; status-only JSON has only its status field. The error-exposure default remains true for compatibility; metadata remains exposed by default too. No breaking default change or version migration is required. Opt in to safer public settings when upgrading. Previously, exposeError: false also removed errors before custom rollup evaluation; rollups now always receive the captured error so output settings cannot alter health evaluation.

Public API overview

Runtime
  • createHealthKit(config) → HealthKit
  • HealthKit: start(), stop(), beginDrain(), handleRequest(req), handleLiveness(), handleReadiness(), handleStartup()
  • toFetchResponse(res, method?) → Fetch Response (HEAD omits the body)
  • createFetchHandler(kit) → (request: Request) => Promise<Response> for Deno, Bun, and Workers
Types
  • HealthkitConfig, CheckConfig, HealthAdapter, AdapterResult, CheckResult, HealthResponse
  • CheckStatus, CheckType, RollupConfig, OutputConfig, DefaultsConfig
  • AgnosticRequest, AgnosticResponse
The canonical type definitions and any future additions live in the healthzkit package under packages/healthzkit in this monorepo.

Startup and drain responses

Configure type: ["startup"] checks for /healthz/startup, or call kit.handleStartup() directly. Startup uses the same execution, cache, rollup, timeout, and output rules as liveness and readiness. Pending initialization is awaited until completion or timeout. Success is not latched: subsequent probes re-evaluate normally. With the default rollup, no matching checks returns 200 with empty checks; a custom rollup still determines the status. Startup does not automatically gate readiness; include initialization checks in both types when needed. handleRequest() and createFetchHandler() recognize exact {basePath}/live, {basePath}/ready, and {basePath}/startup routes. GET and HEAD run the checks; HEAD omits the body. Other methods on these routes return 405 with Allow: GET, HEAD without running checks. Unknown paths return null from handleRequest() and 404 from the Fetch handler. The Fetch handler strips URL query strings. kit.beginDrain() makes readiness return 503 immediately, with health status fail and empty checks. This overrides healthy cached checks, custom rollup, and custom HTTP mappings. Pending readiness requests also fail when their checks finish. Startup and liveness remain independent. See Scheduling for lifecycle behavior.