How to create a health check endpoint

A health check endpoint is a simple URL that monitoring tools can call to check whether your application is running and able to respond.

For a website, API, or SaaS product, this is one of the easiest ways to improve uptime monitoring. Instead of only checking your homepage, you can monitor a dedicated endpoint like:

GET /health

or:

GET /api/health

If the endpoint stops responding or returns an error status code, your monitoring service can send an alert.

What is a health check endpoint?

A health check endpoint is a lightweight API route that reports whether your application is available.

Example:

https://api.example.com/health

A monitoring tool can call this endpoint every minute and check:

  • whether the endpoint responds;

  • whether it returns the expected HTTP status code;

  • whether it responds quickly enough.

For many SaaS products, APIs, dashboards, and backend services, a health check endpoint gives a clearer signal than only monitoring the homepage.

Why health check endpoints matter

A homepage can load while important backend functionality is broken.

For example:

  • the frontend loads, but the API is down;

  • the server is running, but the database is unavailable;

  • the app works from one region but fails from another;

  • the deployment succeeded, but the app is not ready to serve traffic;

  • the website is cached, but dynamic functionality is broken.

A health check endpoint gives your monitoring system a direct target.

Instead of asking:

Does the homepage load?

you ask:

Can the application respond to a basic health request?

Step 1: Choose a simple URL

Use a clear and predictable path.

Common options:

/health

/api/health

/status

Keep it short, stable, and easy to document.

Step 2: Use correct HTTP status codes

The most important part of a health check endpoint is the HTTP status code.

A healthy application should return 200 OK.

An unhealthy application should return 503 Service Unavailable

This makes monitoring simple.

Avoid returning 200 OK when the application is actually unhealthy. That makes your monitoring less useful.

Step 3: Decide what the health check should verify

A health check can be shallow or deeper.

A shallow health check only confirms that the application process is running.

That is simple and fast, but limited.

A deeper health check can verify critical dependencies, such as:

  • database connection;

  • cache connection;

  • queue availability;

  • required environment configuration;

  • critical internal services.

Do not check everything. The endpoint should stay fast and reliable.

A good rule:

Check what is critical, but do not turn /health into a full diagnostic report.

Step 4: Keep it fast

A health check endpoint may be called every minute.

It must be cheap to run.

Avoid:

  • expensive database queries;

  • slow third-party API calls;

  • large data processing;

  • operations that modify data;

  • complex business logic.

Good:

Check that the database responds to a simple SELECT 1.

Bad:

Run a heavy report query every minute.

The health endpoint should help monitoring, not create extra load.

Step 5: Do not expose sensitive information

Health check endpoints are often public or semi-public.

Do not expose:

  • API keys;

  • access tokens;

  • database URLs;

  • internal IP addresses;

  • stack traces;

  • infrastructure details;

  • customer data.

Keep the response minimal.

For public monitoring, even a plain response is enough or no body at all.

Detailed errors should go to internal logs, not to the public response.

Step 6: Protect the endpoint if needed

A basic public health check is usually fine if it exposes no sensitive data.

But if the endpoint checks internal dependencies or reveals operational details, protect it.

Options:

  • require an API key;

  • require a custom header;

  • allow only trusted monitoring IPs;

  • expose a minimal public /health endpoint and keep deeper checks private.

Example:

x-monitoring-key: your-secret-key

For most small SaaS products, start simple. Add protection only if the endpoint exposes something sensitive.

Step 7: Monitor the endpoint

After creating the endpoint, add it to your monitoring service.

Recommended setup:

etting

Value

Method

GET or HEAD

URL

https://api.example.com/health

Expected status

200 OK

Interval

1 minute

Alerts

Slack, Discord, Telegram, or webhook

This gives you a simple signal when your application stops responding correctly.

Example: Node.js health check

Express example:

app.get("/health", async (req, res) => {
  res.sendStatus(200);
});
app.get("/health", async (req, res) => {
  res.sendStatus(200);
});
app.get("/health", async (req, res) => {
  res.sendStatus(200);
});

With a simple database check:

app.get("/health", async (req, res) => {
  try {
    await db.query("SELECT 1");
    res.sendStatus(200);
  } catch {
    res.sendStatus(503);
  }
});
app.get("/health", async (req, res) => {
  try {
    await db.query("SELECT 1");
    res.sendStatus(200);
  } catch {
    res.sendStatus(503);
  }
});
app.get("/health", async (req, res) => {
  try {
    await db.query("SELECT 1");
    res.sendStatus(200);
  } catch {
    res.sendStatus(503);
  }
});

This checks whether the app can reach the database without exposing internal details.

Example: Next.js health check

For Next.js App Router:

// app/api/health/route.ts

export async function GET() {
  return new Response(null, { status: 200 });
}
// app/api/health/route.ts

export async function GET() {
  return new Response(null, { status: 200 });
}
// app/api/health/route.ts

export async function GET() {
  return new Response(null, { status: 200 });
}

With a simple database check:

// app/api/health/route.ts

export async function GET() {
  try {
    await pool.query("SELECT 1");
    return new Response(null, { status: 200 });
  } catch {
    return new Response(null, { status: 503 });
  }
}
// app/api/health/route.ts

export async function GET() {
  try {
    await pool.query("SELECT 1");
    return new Response(null, { status: 200 });
  } catch {
    return new Response(null, { status: 503 });
  }
}
// app/api/health/route.ts

export async function GET() {
  try {
    await pool.query("SELECT 1");
    return new Response(null, { status: 200 });
  } catch {
    return new Response(null, { status: 503 });
  }
}

This is enough for a monitoring service to detect whether the endpoint is healthy.

Common mistakes

Returning 200 for failures

If the app is unhealthy, return 503, not 200.

Making the endpoint too heavy

Do not run expensive logic inside a health check.

Exposing internal details

Do not return secrets, stack traces, connection strings, or infrastructure data.

Final thoughts

A health check endpoint is a simple but useful foundation for website and API monitoring.

Start with:

GET /health

Return 200 OK when the application is healthy and 503 Service Unavailable when it is not. Keep the endpoint fast, safe, and focused on the dependencies that matter most.

For a small SaaS product, this gives your monitoring tool a reliable way to detect backend problems before users report them.