nitrojs / nitrojs/nitro

feat: native healthcheck lifecycle endpoints (`/healthz`, `/livez`, `/readyz`)

Open
#4,451 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement v3
Dominant language
TypeScript
Stars
11.2k
Forks
899
Avg merge
2d 24m
Merged PRs (30d)
40

Description

Describe the feature

Summary

This proposal outlines the addition of standardized, configurable health check endpoints directly into Nitro.

As Nuxt and Nitro applications are often deployed to cloud-native platforms (Kubernetes, AWS ECS, Google Cloud Run, Azure Container Apps, Docker Swarm), there is a need for orchestrators to reliably query application state during startup, steady state, and degraded state.

Currently, Nitro seems to be missing a standard lifecycle state indicator during boot and runtime, leading to deployment challenges like dropped traffic during rolling updates or premature container restarts during slow initialization tasks (e.g., DB migrations, cache priming, or heavy dynamic module loading).

Related issues:

Problem Statement

When deploying Nitro/Nuxt applications in containerized orchestration environments:

  1. Slow Startup Misinterpretation: Orchestrators using simple HTTP ping tests (e.g., GET /) during boot cannot distinguish between a process that is actively initializing versus one that has crashed or deadlocked. If initialization takes 30-60 seconds, orchestrators may repeatedly kill and restart the container before boot completes.
  2. Traffic Routing During Boot: In rolling deployment scenarios, load balancers may route production traffic to a newly spawned container while background server plugins or dynamic module imports are still completing, resulting in user-facing 500 errors.
  3. Inconsistent Developer Implementations: Currently, developers must manually build custom server routes (e.g., server/routes/health.ts), implement global state flags, and manage dependency ping logic themselves. This leads to fragmented, error-prone patterns across different projects.

Proposed Solution: The Lifecycle Health Probe Pattern

Nitro should introduce built-in health endpoints following the Kubernetes Health Endpoint Pattern.

Standard Endpoint Triumvirate

By default, Nitro will expose sub-paths under a configurable base prefix (e.g., /_health or /healthz):

Endpoint Path Probe Type Question Answered Trigger Conditions & Responsibilities
GET /healthz/startup (or /startupz) Startup Probe "Has initialization finished?" Checks if Nitro hooks, server plugins, and startup tasks have resolved.
GET /healthz/liveness (or /livez) Liveness Probe "Is the Node.js loop responsive?" Checks process responsiveness / deadlock detection. Does NOT ping external DBs.
GET /healthz/readiness (or /readyz) Readiness Probe "Can we route user traffic here?" Checks if Nitro is initialized AND critical upstream dependencies (DB, Redis) are reachable.

Lifecycle Behavior & Status Matrix

The table below illustrates status codes and payloads across the complete container lifecycle:

Phase / Scenario /healthz/startup /healthz/liveness /healthz/readiness Action by Orchestrator
Phase A: Booting / Warming Caches 503 Service Unavailable 200 OK 503 Service Unavailable Hold off routing traffic; do NOT restart container.
Phase B: Fully Booted & Ready 200 OK 200 OK 200 OK Route production traffic to container.
Phase C: Upstream Dependency Outage 200 OK 200 OK 503 Service Unavailable Temporarily pull instance out of load balancer; do NOT restart container process.
Phase D: Process Deadlock / Frozen Loop Timeout / 500 Timeout / 500 Timeout / 500 Restart container instance.

API & Configuration Design

Configuration Options (nitro.config.ts)
export default defineNitroConfig({
  healthCheck: {
    enabled: true,
    path: '/healthz', // Base prefix for endpoints
    headers: {
      'Cache-Control': 'no-cache, no-store, must-revalidate'
    },
    // Optional standalone route aliases
    routes: {
      startup: '/healthz/startup',
      liveness: '/healthz/liveness',
      readiness: '/healthz/readiness'
    }
  }
})
Server Plugin Extensions (server/plugins/health.ts)

Developers can register custom health checks directly in Nitro plugins:

export default defineNitroPlugin((nitroApp) => {
  // Register a check that must pass before readiness turns 200 OK
  nitroApp.registerReadinessCheck('database', async () => {
    const { isConnected, latencyMs } = await db.ping();
    if (!isConnected) {
      throw new Error('Database ping failed');
    }
    return { status: 'UP', latencyMs };
  });

  // Register a custom startup task check
  nitroApp.registerStartupCheck('cache-warmup', async () => {
    return await checkCacheStatus();
  });
});

Payload Format Specifications

Startup In-Progress Response (503 Service Unavailable)
{
  "status": "INITIALIZING",
  "timestamp": "2026-07-20T11:25:00.000Z",
  "checks": {
    "nitro:init": "IN_PROGRESS",
    "cache-warmup": "PENDING"
  }
}
Steady-State Ready Response (200 OK)
{
  "status": "UP",
  "timestamp": "2026-07-20T11:26:00.000Z",
  "checks": {
    "nitro:init": "UP",
    "database": "UP",
    "cache-warmup": "UP"
  }
}
Degraded Readiness Response (503 Service Unavailable)
{
  "status": "DOWN",
  "timestamp": "2026-07-20T11:30:00.000Z",
  "checks": {
    "nitro:init": "UP",
    "database": "DOWN (Connection Refused)",
    "cache-warmup": "UP"
  }
}
Additional information
  • Would you be willing to help implement this feature?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the proposed nitro.config.ts healthCheck options and the server/plugins/health.ts registration examples, then inspect Nitro's existing plugin and route lifecycle APIs. Compare the design with the existing server/routes/health.ts pattern. Done should include a settled endpoint, lifecycle, configuration, registration, and response contract with coverage for the documented status matrix.

Written by the indexing model from the issue text.

Assessment

Tech stack
kubernetes, node.js, typescript
Domain
backend-api-design, cloud, observability
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.