Installation
npm install @fullstackhouse/open-mercato-health
Quick Start
Next.js App Router
// app/api/health/live/route.ts
import { createNextHealthHandlers } from '@fullstackhouse/open-mercato-health/integrations/nextjs'
const handlers = createNextHealthHandlers(async () => {
const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')
return createRequestContainer()
})
export const GET = handlers.live
// app/api/health/ready/route.ts
export const GET = handlers.ready
export const dynamic = 'force-dynamic'
Why the lazy loader? Under Turbopack production builds, a static top-level import { createRequestContainer } can be captured as undefined inside the handler closure, causing getContainer is not a function at runtime. Passing a () => import(...) loader defers module resolution until request time and sidesteps the bug. The same pattern applies to createNextReadyHandler.
Endpoints
Liveness (GET /api/health/live)
Returns ok with HTTP 200. No dependencies are checked - this indicates the process is running.
HTTP/1.1 200 OK
Content-Type: text/plain
ok
Readiness (GET /api/health/ready)
Returns JSON with check results. HTTP 200 when all required checks pass, 503 when any required check fails.
{
"status": "ok",
"timestamp": "2026-02-23T12:00:00.000Z",
"durationMs": 18,
"checks": [
{ "name": "Database", "required": true, "status": "ok", "latencyMs": 7, "message": null },
{ "name": "Cache", "required": true, "status": "ok", "latencyMs": 2, "message": null },
{ "name": "Search (Fulltext)", "required": false, "status": "skip", "latencyMs": 0, "message": "Check disabled or not configured" }
]
}
Status Values
| Overall Status | Description | HTTP Code |
|---|
ok | All required checks pass, optional checks pass or skip | 200 |
degraded | All required checks pass, at least one optional check fails | 200 |
fail | Any required check fails | 503 |
| Check Status | Description |
|---|
ok | Check passed |
fail | Check failed |
skip | Check disabled or not configured |
Built-in Checks
| Check | Required | Description |
|---|
| Database | Yes | Executes SELECT 1 via EntityManager |
| Cache | Yes | Performs set/get/delete cycle |
| Queue (Redis) | No | Verifies BullMQ queue connectivity |
| Search (Fulltext) | No | Checks Meilisearch availability |
| Search (Vector) | No | Checks vector search provider |
| KMS (Vault) | No | Verifies encryption service health |
| Email Delivery | No | Checks email provider configuration |
| AI Providers | No | Verifies AI service connectivity |
Configuration
Control which checks run via environment variables:
# Enable/disable individual checks (true, false, or auto)
HEALTH_READY_CHECK_DATABASE_ENABLED=true
HEALTH_READY_CHECK_CACHE_ENABLED=true
HEALTH_READY_CHECK_QUEUE_REDIS_ENABLED=auto
HEALTH_READY_CHECK_SEARCH_FULLTEXT_ENABLED=auto
HEALTH_READY_CHECK_SEARCH_VECTOR_ENABLED=auto
HEALTH_READY_CHECK_KMS_ENABLED=auto
HEALTH_READY_CHECK_EMAIL_DELIVERY_ENABLED=auto
HEALTH_READY_CHECK_EXTERNAL_AI_PROVIDERS_ENABLED=auto
true: Always run the checkfalse: Never run the checkauto (default): Run if the service is configured
Custom Checks
Create custom health check strategies by extending BaseReadyCheckStrategy:
import { BaseReadyCheckStrategy } from '@fullstackhouse/open-mercato-health'
import type { CheckKey, HealthContainer } from '@fullstackhouse/open-mercato-health'
class StripeReadyCheckStrategy extends BaseReadyCheckStrategy {
readonly id = 'STRIPE' as CheckKey