Framework Guide

Node.js API Monitoring

Set up health check endpoints and uptime monitoring for your Node.js application. Works with Express, Fastify, Koa, and native HTTP.

Why Monitor Your Node.js App?

Node.js applications can fail silently in production. The event loop might be blocked, database connections might pool up, or memory leaks might cause gradual degradation. External monitoring catches these issues before users notice.

  • Event loop blocking -- CPU-intensive operations can freeze your app without crashing it
  • Memory leaks -- Node.js apps can slowly consume memory until they OOM crash
  • Dependency failures -- Database, Redis, or third-party API outages cascade through your app
  • Unhandled rejections -- Uncaught promise rejections can leave your app in a broken state

Basic Health Endpoint (Native HTTP)

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/health' && req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({
      status: 'healthy',
      timestamp: new Date().toISOString()
    }));
    return;
  }
  // ... your other routes
});

server.listen(3000);

Express Health Endpoint

const express = require('express');
const app = express();

// Simple liveness check
app.get('/health', (req, res) => {
  res.json({ status: 'healthy' });
});

// Comprehensive readiness check
app.get('/ready', async (req, res) => {
  try {
    // Check database
    await db.query('SELECT 1');

    // Check Redis
    await redis.ping();

    res.json({
      status: 'ready',
      checks: {
        database: 'ok',
        redis: 'ok'
      }
    });
  } catch (error) {
    res.status(503).json({
      status: 'not ready',
      error: error.message
    });
  }
});

Fastify Health Endpoint

const fastify = require('fastify')();

fastify.get('/health', async (request, reply) => {
  return { status: 'healthy' };
});

// With schema validation
fastify.get('/ready', {
  schema: {
    response: {
      200: {
        type: 'object',
        properties: {
          status: { type: 'string' },
          uptime: { type: 'number' }
        }
      }
    }
  }
}, async (request, reply) => {
  return {
    status: 'ready',
    uptime: process.uptime()
  };
});

What to Include in Health Checks

  • Database connectivity — Can you query the database?
  • Cache connectivity — Is Redis/Memcached reachable?
  • Memory usage — process.memoryUsage()
  • Uptime — process.uptime()
  • Version — Useful for debugging deployments

Complete Example with Dependencies

app.get('/health', async (req, res) => {
  const health = {
    status: 'healthy',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    version: process.env.npm_package_version || '1.0.0',
    checks: {}
  };

  // Check database with timeout
  try {
    const dbStart = Date.now();
    await Promise.race([
      db.query('SELECT 1'),
      new Promise((_, reject) =>
        setTimeout(() => reject(new Error('timeout')), 5000)
      )
    ]);
    health.checks.database = {
      status: 'ok',
      responseTime: Date.now() - dbStart
    };
  } catch (error) {
    health.status = 'unhealthy';
    health.checks.database = {
      status: 'error',
      message: error.message
    };
  }

  const statusCode = health.status === 'healthy' ? 200 : 503;
  res.status(statusCode).json(health);
});

Best Practices

  • Keep it fast — Health checks should respond in under 500ms
  • No auth required — Monitoring services need unauthenticated access
  • Add timeouts — Don't let slow dependencies hang the health check
  • Log health check traffic separately — Avoid cluttering your logs

Common Node.js Production Issues

Event Loop Blocking

CPU-intensive operations (JSON parsing large payloads, image processing, crypto) can block the event loop and freeze all requests. Your app appears "up" but responds to nothing. Health checks with timeouts catch this.

Memory Leaks

Closures, global caches, and event listener leaks slowly consume memory. Monitor process.memoryUsage().heapUsed in your health check. Alert when it exceeds 80% of your container limit.

Connection Pool Exhaustion

Database connection pools fill up under load, causing new queries to hang. Include a database ping in your readiness check to catch pool exhaustion early.

Uncaught Exceptions

An uncaught exception or unhandled promise rejection can crash your Node.js process. Use process managers like PM2 to auto-restart, and external monitoring to detect the downtime gap.

Frequently Asked Questions

What should a Node.js health check endpoint return?
A health check should return HTTP 200 with a JSON body containing at minimum a status field. For comprehensive checks, include database connectivity, cache status, memory usage (process.memoryUsage()), uptime (process.uptime()), and app version. Return 503 if any critical dependency is unhealthy.
Should I use /health or /healthz?
Both work. /health is more readable, while /healthz follows Kubernetes conventions. If deploying to K8s, use /healthz for liveness and /readyz for readiness probes. For external monitoring with UptimeSignal, either path works.
How do I prevent health checks from cluttering my logs?
In Express, add middleware that skips logging for health routes: check req.path === '/health' before passing to your logger middleware. In Fastify, use the disableRequestLogging option for the health route.
Should my health endpoint require authentication?
No. Health check endpoints should be unauthenticated so monitoring services can access them without managing credentials. If you're concerned about exposing information, return minimal data (just status: "healthy") on the public endpoint and a detailed version behind auth.
How often should I check my Node.js API health?
For production APIs, check every 1-5 minutes. UptimeSignal's free tier checks every 5 minutes, which catches most outages quickly. Pro tier supports 1-minute intervals for faster detection. Avoid checking more frequently than every 30 seconds to prevent unnecessary load.

Monitor your Node.js API

Add your health endpoint to UptimeSignal and get alerted when it fails. Free tier includes 25 monitors.

Start monitoring free →

No credit card required. Commercial use allowed.

More Framework Guides