What Is a Health Check Endpoint? The Beginner's Guide (Liveness vs Readiness, and What NOT to Check)

CodexFuse Team · 2026-11-04T12:39:06.666Z · 16 min read min read

A health check endpoint is a small HTTP endpoint — usually GET /health — that your application exposes so the infrastructure around it can ask two questions: is this instance alive, and can it take traffic right now? Load balancers, container orchestrators, and uptime monitors poll it every few seconds, and the answer they get decides whether your code keeps serving users, gets restarted, or gets quietly pulled out of rotation. Consider this your health check endpoint explained simply, with production rules attached. When you run containers, the details of how that polling works are worth learning once and getting right — our Docker beginner guide covers the container side of the same story. This guide explains what a health check endpoint is, who consumes it, how Kubernetes' three probes differ, how Docker's HEALTHCHECK works, and — just as important — what a health endpoint must never do.

What is a health check endpoint?

A health check endpoint is a dedicated URL your service exposes so automated systems can verify, without human help, whether the instance is working. It answers in the language machines already speak: an HTTP status code. A 200 OK means "healthy — send me traffic," while a non-200 response like 503 Service Unavailable means "something is wrong — stop sending me traffic." As one widely-read Node.js health-check guide puts it, the endpoint is "the interface between your application and the infrastructure that decides whether your application lives or dies, receives traffic or gets replaced" (iurii.rogulia.fi, "Health Check Endpoint in Node.js: Liveness vs Readiness," read November 4, 2026).

Kubernetes formalized the idea into three separate checks, and that three-way split is the mental model everything else in this guide hangs on:

  1. Liveness — "Is this process still alive, or has it become a zombie?" If the liveness check fails, Kubernetes restarts the container.
  2. Readiness — "Is this instance ready to serve requests right now?" If the readiness check fails, the pod is pulled out of the load balancer rotation. No restart — traffic just stops arriving.
  3. Startup — "Has this container finished booting?" Kubernetes waits for the startup check to pass before it even runs the liveness and readiness checks, so slow-starting apps are not killed for being slow.

The single sentence to carry away: liveness decides restarts, readiness decides traffic, and startup decides when those two start watching.

Who polls your health endpoint, and what do they do with the answer?

Four kinds of consumers poll health endpoints, and each one wants something slightly different from the answer. First is the kubelet, the agent on every Kubernetes node — the official Kubernetes docs define a probe as "a diagnostic performed periodically by the kubelet on a container," and it is the kubelet that acts on the result, restarting containers and setting pod conditions (kubernetes.io, "Liveness, Readiness, and Startup Probes," read November 4, 2026). Second is the load balancer, which treats the endpoint as a routing vote: as iurii.rogulia.fi puts it, "the load balancer cares about the HTTP status," so a 503 pulls the instance out of rotation. Third is the orchestrator's control plane: when readiness fails, the kubelet sets the pod's Ready condition, the EndpointSlice controller removes the pod's IP from the Service's endpoints, and kube-proxy or your ingress controller stops routing traffic to it — the pod itself keeps running. Fourth is your monitoring system, which reads the response body rather than just the status code; the same guide notes that "your monitoring system reads the response body and alerts on degraded status," while the balancer cares only about the code.

This split is why the body of a health response matters as much as its status. Include a version field so you can confirm the instance you are looking at is running the code you just deployed, and an uptime field — that field is what catches restart loops, where a pod keeps dying and respawning (iurii.rogulia.fi). Where the whole thing runs matters too: your health endpoints are only as reliable as the machines under them, which is why our VPS hosting guide is the natural companion read for anyone self-hosting this setup.

Liveness vs readiness: what is the difference?

Liveness asks whether the process is alive and making progress; readiness asks whether the instance should receive traffic. The failure actions are deliberately different, and mixing them up is the most common health-check mistake in production.

A liveness probe catches the "running but stuck" state — a deadlock where the application is up but unable to make progress. The Kubernetes docs say restarting a container in such a state "can help to make the application more available despite bugs," and the failure action is exactly that: the kubelet restarts the container. A readiness probe, by contrast, never restarts anything. When it fails, "the EndpointSlice controller removes the Pod's IP address from the EndpointSlices of all Services that match the Pod" (kubernetes.io) — the pod stops getting traffic but keeps running, which is exactly what you want when a dependency is temporarily down: pulling traffic is gentler than killing the process.

There is a well-known recommended pairing. The Kubernetes docs describe "a common pattern for liveness probes" as using "the same low-cost HTTP endpoint as for readiness probes, but with a higher failureThreshold" — the pod is observed as not-ready for a while before it is hard-killed, so transient blips cost you traffic, not restarts. And when an app strictly depends on back-end services, the docs suggest implementing both: the liveness probe passes "when the app itself is healthy," while the readiness probe "additionally checks that each required back-end service is available."

What does a startup probe do?

A startup probe exists for applications that need a long time to boot — large caches to warm, migrations to run, models to load. Kubernetes probes documentation states that "if a startup probe is configured, Kubernetes does not execute liveness or readiness probes until the startup probe succeeds, allowing the application time to finish its initialization." Unlike the other two, it runs only at startup, never periodically. If it fails, the kubelet kills the container and the restart policy takes over. Before startup probes existed, the only tool for this was a long initialDelaySeconds on the liveness probe — a guess about boot time that punished both slow boots and fast ones. The dedicated probe replaced that guess with a real signal. Our Kubernetes beginner guide walks through running your first cluster if you want to try these probes on your own machine.

How do you configure the probes? The five numbers that matter

Every Kubernetes liveness readiness probe — liveness, readiness, or startup — is tuned with the same five fields, and the official docs give their defaults verbatim. Know these and you can read any probe configuration at a glance:

FieldWhat it meansDefault
initialDelaySecondsSeconds after container start before the probe first runs0
periodSecondsHow often, in seconds, the probe runs (minimum 1)10
timeoutSecondsSeconds after which the probe is considered failed (minimum 1)1
successThresholdConsecutive successes needed to recover from failure1 — and it must be 1 for liveness and startup probes
failureThresholdConsecutive failures before the probe is declared failed3

Each probe also uses exactly one check mechanism: exec (a command in the container, exit code 0 means success), httpGet (a GET request where status codes 200–399 count as success), tcpSocket (a successful TCP handshake means the port is open), or grpc (a response of SERVING means success). One caution from the official docs worth heeding: exec probes fork a new process on every check, so "configuring any probe with exec mechanism might introduce an overhead on the cpu usage of the node" — prefer httpGet for anything that runs every few seconds. All five defaults and all four mechanisms above are from kubernetes.io, "Liveness, Readiness, and Startup Probes," read November 4, 2026.

How do you add a health check in Docker?

Docker's answer to the same problem is the HEALTHCHECK instruction — the Docker healthcheck directive you add in your Dockerfile. The official Docker docs explain that it "tells Docker how to test a container to check that it's still working," and that it "can detect cases such as a web server stuck in an infinite loop and unable to handle new connections, even though the server process is still running" (docs.docker.com, Dockerfile reference, read November 4, 2026). It comes in two forms: HEALTHCHECK [OPTIONS] CMD command, which runs a command inside the container, and HEALTHCHECK NONE, which disables any health check inherited from the base image. There can only be one HEALTHCHECK per Dockerfile — if you write more than one, only the last takes effect.

The instruction is tuned with five flags, and again the docs give the defaults verbatim:

FlagWhat it meansDefault
--intervalTime between checks30s
--timeoutMaximum time one check may run (a slow check is killed with SIGKILL and counts as failed)30s
--start-periodGrace period after container start; failures here do not count toward retries0s
--start-intervalCheck interval during the start period (needs Docker Engine 25.0 or later)5s
--retriesConsecutive failures before the container is marked unhealthy3

The command's exit code is the verdict: 0 means healthy, 1 means unhealthy, and 2 is reserved — the docs say "don't use this exit code." A container with a health check moves through three states: it starts as starting, becomes healthy whenever a check passes, and becomes unhealthy after enough consecutive failures. One Docker-specific reality to design around: unlike Kubernetes' readiness, Docker's single health check has no "stop sending traffic" gear. As iurii.rogulia.fi warns, "in Docker Compose, a failed healthcheck always means a restart, not a graceful drain," so if your Docker health check verifies external dependencies like Postgres or Redis and those go down, Docker will restart your container — "even though a restart cannot fix a database outage." Keep the interval long (30s or more) and retries generous (3–5) in Docker land, and point the check at the lightweight liveness endpoint, not the full dependency suite.

What should a health endpoint check — and what should it never check?

The useful rule, repeated across every source read for this guide, is that a health check should verify only the things whose failure should take this instance out of rotation — and it must answer fast. Here is the practical split:

Check thisNever check this
A lightweight database query through your connection pool (catches pool exhaustion, not just network reachability)External third-party APIs like payment or email providers — their transient failures should not take your service offline
A cache ping, e.g. Redis PING, if you depend on it for serving requestsBusiness-logic assertions — health is an infrastructure concern, not a data-consistency check
Disk writability and available space, if your app writes filesAnything that takes more than about a second under normal conditions
Your own process state (event loop responsive, no deadlock) — the liveness laneBack-end dependencies in the liveness check — keep liveness to "am I alive?"

Two one-time lessons carry this section. First, never hardcode a 200: "If your health check endpoints return a hard-coded response then you don't actually know the health of your service" (emmer.dev, "Writing Meaningful Health Check Endpoints," read November 4, 2026). A hardcoded endpoint is a comforting lie that the infrastructure believes. Second, the cardinal rule from a 2026 Kubernetes probes guide: liveness probes must never check external dependencies. If your database goes down and your liveness probe fails, Kubernetes restarts your pod; the new pod still cannot reach the database, so it gets restarted too — "now you have a restart loop on top of a database outage" (dev.to, "Kubernetes Health Probes Done Right," read November 4, 2026). Liveness answers "is the process healthy"; readiness answers "can it serve." Keep the two questions on separate endpoints.

How fast must a health check answer?

Faster than you think. The single most important constraint on a health endpoint is that it must never hang: "If your database connection pool is exhausted, a SELECT 1 query will sit in the queue waiting for a connection to become available. Without a timeout, your health check hangs for 30 seconds, the load balancer times out waiting for a response, and it marks your instance unhealthy — not because it is, but because the health check itself blocked" (iurii.rogulia.fi). The practical budgets from production practice, all from the same guide:

CheckTimeout budget
Database query2s (a local SELECT 1 should finish in under 5ms — if it takes 2s, something is wrong)
Redis ping1s
Queue depth counts1.5s
Whole endpointWell under 3s total
Probe timeout (Docker/Kubernetes)5–10s, to give the endpoint headroom

Implement each check with its own timeout — the guide's pattern is racing each dependency check against a timer — because bounding the endpoint's response time is not the same as canceling the stuck operation behind it. The timer saves the health check; cleaning up the stuck query is separate work.

A minimal health endpoint you can copy

The simplest useful liveness handler is almost embarrassingly small. From a Go health-check guide for Kubernetes (oneuptime.com, "Health Checks in Go for Kubernetes," read November 4, 2026):

func livenessHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
}

That answers "is the process alive?" and nothing else — which is exactly what liveness should answer. The readiness side is where the dependency verification lives. The Hono (Node.js) pattern from iurii.rogulia.fi wires two endpoints: /health/ready runs the full dependency verification with per-check timeouts and returns 200 when the service is ok or degraded — "the load balancer should still route traffic" when degraded — and 503 only when truly unhealthy, so the instance leaves rotation. His advice for Docker users is to point the container HEALTHCHECK at the lightweight /health/live endpoint instead, keeping the heavy verification for Kubernetes readiness where a failure costs traffic rather than a restart.

What are the /health endpoint best practices — and the mistakes that break them?

Health checks are supposed to reduce outages, but five classic mistakes turn them into the cause. First, a liveness probe that checks the database, which creates the restart loop described above: the pod restarts because a dependency is down, and the restart fixes nothing. Second, an exec-based probe on a busy cluster, where every check forks processes and the monitoring itself loads the nodes. Third, a successThreshold greater than 1 on a liveness or startup probe — the Kubernetes API expects 1 there, and anything else is a misconfiguration. Fourth, a slow health check under load: the official Kubernetes docs warn that "incorrect implementation of liveness probes can lead to cascading failures," producing "restarting of container under high load; failed client requests as your application became less scalable; and increased workload on remaining pods due to some failed pods." Fifth, a Docker health check that verifies external services, which restarts containers during someone else's outage. The unifying fix is the same in all five cases: make liveness cheap and dependency-free, give readiness the real checks, and give every check a timeout shorter than the probe that watches it. The probe configuration half of this equation is a natural next read in our Kubernetes probes guide section on Deployments.

Sources

  • Kubernetes official documentation, "Liveness, Readiness, and Startup Probes" (https://kubernetes.io/docs/concepts/workloads/pods/probes/) — probe definitions, the cascading-failure caution, the five configuration fields and their defaults, the four check mechanisms, all quoted verbatim; read November 4, 2026.
  • Docker official documentation, Dockerfile reference, HEALTHCHECK section (https://docs.docker.com/reference/dockerfile/) — syntax forms, the five flags and their defaults, exit-code meanings, health-state transitions; page updated October 8, 2026, read November 4, 2026.
  • iurii.rogulia.fi, "Health Check Endpoint in Node.js: Liveness vs Readiness" (https://iurii.rogulia.fi/blog/healthcheck-endpoint-production) — the what-not-to-check list, the never-hang rule, per-check timeout budgets, the Hono readiness/liveness split, Docker Compose restart caveat; read November 4, 2026.
  • dev.to, "Kubernetes Health Probes Done Right: Liveness, Readiness, and Startup" (https://dev.to/young_gao/kubernetes-health-probes-done-right-liveness-readiness-and-startup-5g7g) — the liveness-must-never-check-dependencies cardinal rule and the restart-loop hazard; read November 4, 2026.
  • oneuptime.com, "Health Checks in Go for Kubernetes" (https://oneuptime.com/blog/post/2026-01-07-go-health-checks-kubernetes/view) — the minimal Go liveness handler and the keep-liveness-simple rule; read November 4, 2026.
  • emmer.dev, "Writing Meaningful Health Check Endpoints" (https://emmer.dev/blog/writing-meaningful-health-check-endpoints/) — the never-hardcode-200 lesson and the healthy/unhealthy response anatomy; read November 4, 2026.
  • medium.com, "Liveness vs Readiness Probes in Kubernetes" (https://medium.com/@talkoragi25/liveness-vs-readiness-probes-in-kubernetes-what-they-are-who-watches-them-and-how-to-configure-515b201d432f) — the kubelet-to-EndpointSlice-to-kube-proxy consumer chain; read November 4, 2026.
  • learnwisej.com, "Deployment, Diagnostics, Load Balancing & Capstone Delivery" lesson guide — the cheap-and-honest health-check definition and the check-only-what-takes-the-node-out-of-rotation rule; read November 4, 2026.
  • startdebugging.net, "How to add a health check endpoint to a minimal API in ASP.NET Core 11" — liveness answers "is this process wedged and does it need a restart"; read November 4, 2026.
  • thediplomariot.com, "Health Check Endpoint: Ensure Your Services Are Alive" — the URL-plus-200/503 response convention; read November 4, 2026.
  • lessthanhero.io, "Health Endpoints" — the liveness/readiness route split and the poller concept; read November 4, 2026.
  • apipark.com, "Python Health Check Endpoint Example for Reliable Application Monitoring" — the 200-OK-healthy / 503-unhealthy status-code convention; read November 4, 2026.

Frequently Asked Questions

What is the difference between liveness and readiness probes?

Liveness asks "is this process alive?" and a failed liveness probe restarts the container; readiness asks "can this instance serve traffic right now?" and a failed readiness probe only removes the pod from the load balancer rotation, with no restart. Keep liveness cheap and dependency-free, and let readiness verify the dependencies.

Should my liveness probe check the database?

No. If the database goes down, a database-checking liveness probe fails, Kubernetes restarts the pod, and the new pod still cannot reach the database — a restart loop on top of the outage. Check back-end services in the readiness probe, where a failure costs traffic instead of restarts.

What HTTP status should a health endpoint return?

Return 200 OK when the instance is healthy (or degraded but still able to serve), and 503 Service Unavailable when it should leave rotation. Kubernetes treats HTTP 200–399 as probe success. Never hardcode a 200 — the endpoint must reflect real checks.

How often does Kubernetes check my probes?

Every 10 seconds by default (periodSeconds: 10), with a 1-second timeout (timeoutSeconds: 1) and 3 consecutive failures (failureThreshold: 3) before a probe is declared failed. That means a broken liveness probe triggers a restart roughly 30 seconds after the first failure with defaults.

Does a failed Docker HEALTHCHECK restart my container?

Docker marks the container unhealthy after the configured number of consecutive failures (default 3), and in Docker Compose an unhealthy container is restarted — there is no graceful "stop sending traffic" gear like Kubernetes readiness. Design Docker health checks to verify the container itself, not external dependencies, and keep the interval at 30 seconds or longer.

Featured on Twelve Tools Hunt for Tools Featured on LaunchBuff Launch Llama Tools Launch your MCP Top Web Development Companies in the US - OnToplist.com Designer Listings Listed on SeeWhatNewAI