Skip to content

Health Check Endpoints Explained — Complete Beginner's Guide

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Health Check Endpoints Explained. We cover key concepts, practical examples, and best practices to help you master this topic.

Health check endpoints are HTTP endpoints that report whether a service is running correctly, enabling Orchestration systems and load balancers to make automated decisions about traffic routing and restarts.

What You'll Learn

By the end of this tutorial, you will understand what health check endpoints are, the difference between readiness and liveness probes, and how they enable self-healing infrastructure.

Why It Matters

Without health checks, orchestrators and load balancers operate blind. A crashed service still receives traffic, a restart never triggers, and operators must manually detect and respond to failures.

Real-World Use

DodaTech's Kubernetes cluster runs 200+ Microservices, each with at least two health endpoints. The platform team monitors aggregate health across all services on a single dashboard.

Health Check Learning Path

flowchart LR
  A[Graceful Shutdown Project] --> B[Health Check Endpoints]
  B --> C[Readiness vs Liveness]
  B --> D[Implementation]
  B --> E[Kubernetes]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

What Is a Health Check Endpoint?

A health check endpoint is a dedicated HTTP URL that returns the status of a service. It typically returns a 200 status when healthy and a non-200 status when unhealthy.

const http = require("http");

function createBasicHealthEndpoint(port = 8080) {
  const server = http.createServer((req, res) => {
    if (req.url === "/healthz") {
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(JSON.stringify({
        status: "healthy",
        timestamp: new Date().toISOString()
      }));
    } else {
      res.writeHead(404);
      res.end();
    }
  });

  server.listen(port, () => {
    console.log(`Health endpoint at http://localhost:${port}/healthz`);
  });

  return server;
}

createBasicHealthEndpoint();
// Health endpoint at http://localhost:8080/healthz
// GET /healthz -> {"status": "healthy", "timestamp": "2026-06-28T12:00:00.000Z"}

Readiness vs Liveness Probes

There are three types of health probes, each with a different purpose.

Probe Type Purpose What Happens on Failure
Readiness Is the service ready to receive traffic? Removed from load balancer
Liveness Is the service alive and running? Container is restarted
Startup Has the service finished starting? Delays readiness/liveness checks
class ProbeTypes {
  static explain() {
    const probes = [
      {
        name: "Readiness",
        endpoint: "/readyz",
        healthyResponse: "200 OK",
        unhealthyResponse: "503 Service Unavailable",
        action: "Stop routing traffic to this instance"
      },
      {
        name: "Liveness",
        endpoint: "/healthz",
        healthyResponse: "200 OK",
        unhealthyResponse: "503 Service Unavailable",
        action: "Restart the container"
      },
      {
        name: "Startup",
        endpoint: "/startupz",
        healthyResponse: "200 OK",
        unhealthyResponse: "503 Service Unavailable",
        action: "Delay other probes until ready"
      }
    ];

    probes.forEach(p => {
      console.log(`${p.name} (${p.endpoint}): ${p.action}`);
    });
  }
}

ProbeTypes.explain();
// Readiness (/readyz): Stop routing traffic to this instance
// Liveness (/healthz): Restart the container
// Startup (/startupz): Delay other probes until ready

Why Health Checks Matter

Health checks enable automated recovery and zero-downtime operations.

function simulateWithoutHealthChecks() {
  let serviceHealthy = false;
  let crashedTime = Date.now();
  let downtime = 0;

  for (let minute = 0; minute < 60; minute++) {
    if (!serviceHealthy) {
      downtime++;
    }
    if (minute === 5) {
      console.log("Service crashed at minute 5");
      console.log("No health check to detect or restart");
    }
    if (minute === 45) {
      console.log("Operator manually detects failure at minute 45");
      serviceHealthy = true;
    }
  }
  console.log(`Total downtime: ${downtime} minutes`);
}

function simulateWithHealthChecks() {
  let serviceHealthy = false;
  let crashedTime = Date.now();
  let downtime = 0;
  let healthCheckInterval = 1;

  for (let minute = 0; minute < 60; minute++) {
    if (!serviceHealthy) {
      downtime++;
    }
    if (minute === 5) {
      console.log("Service crashed at minute 5");
      serviceHealthy = false;
    }
    if (minute === 6 && !serviceHealthy) {
      console.log("Health check detected failure at minute 6");
      console.log("Orchestrator restarts service");
      serviceHealthy = true;
      crashTime = 0;
    }
  }
  console.log(`Total downtime: ${downtime} minutes`);
}

simulateWithoutHealthChecks();
simulateWithHealthChecks();
// Total downtime: 40 minutes (without health checks)
// Total downtime: 1 minute (with health checks)

Common Mistakes

  1. Using the same endpoint for readiness and liveness -- Readiness and liveness serve different purposes. A service can be alive but not ready (e.g., during startup or shutdown).

  2. Not including dependency status -- A health check that returns healthy when the database is down creates false confidence. Check critical dependencies.

  3. Making health checks too expensive -- Health checks run every few seconds. Don't make expensive database queries or complex computations in health check handlers.

  4. Not logging health check failures -- When a health check fails, log why. This helps operators diagnose whether failures are transient or persistent.

  5. Returning 200 for all cases -- A health check should return a non-200 status when unhealthy. 503 is the standard status for unhealthy services.

Practice Questions

  1. What is the difference between readiness and liveness probes? Readiness controls traffic routing (remove from service). Liveness controls restart behavior (restart container).

  2. Why should health check endpoints be lightweight? They're called frequently (every 5-15 seconds). Expensive health checks increase load and can cause cascading failures.

  3. What HTTP status code should a healthy endpoint return? 200 OK. Unhealthy endpoints should return 503 Service Unavailable.

  4. Challenge: Implement a health check that returns different status codes for liveness, readiness, and startup probes.

const http = require("http");

function createProbeAwareServer() {
  let ready = false;
  let alive = true;

  setTimeout(() => { ready = true; }, 5000);

  return http.createServer((req, res) => {
    const body = JSON.stringify({
      status: "ok",
      probes: { ready, alive }
    });

    if (req.url === "/healthz") {
      res.writeHead(alive ? 200 : 503);
    } else if (req.url === "/readyz") {
      res.writeHead(ready ? 200 : 503);
    } else if (req.url === "/startupz") {
      res.writeHead(ready ? 200 : 503);
    } else {
      res.writeHead(404);
    }

    res.end(body);
  });
}

const server = createProbeAwareServer();
server.listen(8080);

FAQ

Should health checks be on a separate port?

Yes, for production. A separate health port (e.g., 8081) ensures health checks remain available even if the main application port is overloaded or closed during shutdown.

How often should health checks run?

Every 5-15 seconds for readiness and liveness, every 30-60 seconds for startup. Adjust based on how quickly you need to detect failures.

Can health checks cause cascading failures?

Yes. If a health check makes an expensive database query and the database is slow, all services checking that health endpoint will also slow down.

What format should the health check response use?

JSON is standard. Include status, timestamp, and optionally dependency statuses. Keep it simple and parseable.

Should I add authentication to health check endpoints?

No. Health check endpoints should be accessible without authentication. Adding auth creates a dependency that can itself fail.

Mini Project

Build a basic health check server with three endpoints (liveness, readiness, startup) that returns structured JSON with status codes, timestamps, and dependency status.

const http = require("http");

function buildHealthServer() {
  const state = {
    started: Date.now(),
    ready: false,
    healthy: true,
    dependencies: { database: true, cache: true }
  };

  setTimeout(() => { state.ready = true; }, 3000);

  const server = http.createServer((req, res) => {
    const response = {
      service: "my-app",
      version: "1.0.0",
      timestamp: new Date().toISOString(),
      uptime: Math.floor((Date.now() - state.started) / 1000)
    };

    if (req.url === "/healthz") {
      const alive = state.healthy;
      res.writeHead(alive ? 200 : 503);
      response.status = alive ? "alive" : "dead";
    } else if (req.url === "/readyz") {
      res.writeHead(state.ready ? 200 : 503);
      response.status = state.ready ? "ready" : "not ready";
    } else if (req.url === "/startupz") {
      res.writeHead(state.ready ? 200 : 503);
      response.status = state.ready ? "started" : "starting";
    } else {
      res.writeHead(404);
      response.status = "not found";
    }

    response.dependencies = state.dependencies;
    res.setHeader("Content-Type", "application/json");
    res.end(JSON.stringify(response));
  });

  return server;
}

buildHealthServer().listen(8080);
console.log("Health check server started on :8080");

What's Next

Now that you understand health check basics, learn the difference between readiness and liveness probes in detail. Then explore different types of health checks.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro