DEV Community

Cover image for Prometheus and Grafana Monitoring for a Node.js API

Prometheus and Grafana Monitoring for a Node.js API

“Monitoring is not about collecting data, it's about gaining visibility into what truly matters.”

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Architecture Overview
  4. Step 1: Create a Sample Node.js API
  5. Step 2: Dockerize the Node.js App
  6. Step 3: Configure Prometheus
  7. Step 4: Run Prometheus & Grafana with Docker
  8. Step 5: Configure Grafana Dashboard
  9. Step 6: Verify Metrics & Simulate Load
  10. Interesting Facts & Statistics
  11. FAQs
  12. Key Takeaways
  13. Conclusion

1. Introduction

Modern applications rely heavily on APIs, and Node.js APIs are widely used due to their high performance and scalability. However, without proper monitoring, even small issues - such as high latency or memory leaks - can quickly escalate into serious production outages.

In this Proof of Concept (POC), we demonstrate how to monitor a Node.js API using Prometheus for metrics collection and Grafana for visualization and alerting.

Goals of this POC

  • Monitor API performance in real time
  • Identify latency and error issues
  • Visualize metrics using dashboards
  • Prepare a production-ready observability foundation

2. Prerequisites

You should have the following:

  • Linux or macOS system
  • Docker & Docker Compose installed
  • Basic knowledge of Node.js
  • Required open ports: 3000, 9090, 3001

3. Architecture Overview

Architecture Flow

  • Node.js API exposes a /metrics endpoint
  • Prometheus scrapes metrics every 5 seconds
  • Grafana visualizes metrics from Prometheus
  • Alerts trigger when defined thresholds are exceeded

4. Step 1: Create a Sample Node.js API

Create project directory

  • mkdir nodejs-monitoring-poc
  • cd nodejs-monitoring-poc
  • mkdir app
  • cd app
  • npm init -y

Install dependencies

  • npm install express prom-client

Create index.js

const express = require('express');
const client = require('prom-client');
const app = express();
const PORT = 3000;

// Collect default system metrics
client.collectDefaultMetrics({ timeout: 5000 });
// Custom HTTP request counter
const httpRequestCounter = new client.Counter({
 name: 'http_requests_total',
 help: 'Total number of HTTP requests',
 labelNames: ['method', 'route', 'status']
});

// Middleware to track requests
app.use((req, res, next) => {
 res.on('finish', () => {
   httpRequestCounter.labels(req.method, req.path, res.statusCode).inc();
 });
 next();
});

// Sample API endpoint
app.get('/api/hello', (req, res) => {
 res.json({ message: 'Hello from Node.js API' });
});

// Metrics endpoint
app.get('/metrics', async (req, res) => {
 res.set('Content-Type', client.register.contentType);
 res.end(await client.register.metrics());
});

app.listen(PORT, () => {
 console.log(`Node.js app running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Run locally

5. Step 2: Dockerize the Node.js App

Create a Dockerfile inside the app/ directory:

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
Enter fullscreen mode Exit fullscreen mode

6. Step 3: Configure Prometheus

Create Prometheus directory

cd ..
mkdir prometheus
Enter fullscreen mode Exit fullscreen mode

Create prometheus.yml

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'docker'
    static_configs:
      - targets: ['grafana:3000', 'prometheus:9090']
      - targets: ['poc-addweb-app.addwebprojects.com']
Enter fullscreen mode Exit fullscreen mode

7. Step 4: Run Prometheus & Grafana with Docker Compose

Create docker-compose.yml

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./.prome/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    ports:
      - "3003:3000"
    depends_on:
      - prometheus
Enter fullscreen mode Exit fullscreen mode

Start the stack
docker-compose up -d
Verify services

Username: admin
Password: admin

8. Step 5: Configure Grafana Dashboard

Add Prometheus Data Source

  1. Grafana → Settings → Data Sources
  2. Select Prometheus
  3. URL: https://promotheus.65.1.109.206.nip.io
  4. Click Save & Test Create Dashboard Panels (PromQL) Total Requests sum(node_app_total_requests)

Uptime Second
rate(node_app_uptime_seconds])

Memory Usage
Process_resident_memory_bytes
grafana_Process_resident_memory_bytes

“In production, everything fails eventually. Monitoring tells you when and why.”

9. Step 6: Verify Metrics & Simulate Load

Generate traffic
sudo apt install wrk -y
wrk -t8 -c500 -d120s https://poc-addweb-app.addwebprojects.com/
Verify

  • Prometheus → Status → Targets → UP
  • Grafana dashboard shows increasing metrics

Practical Demonstration (Images Explained)

Step 1: Verify Prometheus Targets Are Healthy

Navigate to the Prometheus Targets page at https://promotheus.65.1.109.206.nip.io/targets to confirm all scrape targets are reachable. The "State" column must show "UP" for every endpoint.

Figure 1: Prometheus Target Health page displaying all three endpoints under the "docker" job (poc-addweb-app, grafana:3000, prometheus:9090) with State = UP and scrape latency under 30 ms. This confirms that Prometheus is successfully collecting metrics from the Node.js application, its own internal metrics, and Grafana.

Step 2: Access the Grafana Dashboard
Open the Grafana web interface at https://poc-grafana.addwebprojects.com. The default login credentials are:
Username: admin
Password: admin

Figure 2: Grafana v12.3.3 login page served at poc-grafana.addwebprojects.com. After authentication, you are redirected to the Home dashboard where data sources and panels can be configured.
Open the "Node-Application" dashboard in Grafana. The "Up Status" panel uses the PromQL query "up" to display a binary availability indicator (1 = reachable, 0 = unreachable) for each monitored target.

Figure 3: Grafana "Up Status" panel showing all three services (Grafana at grafana:3000, Node.js app at poc-addweb-app.addwebprojects.com, and Prometheus at prometheus:9090) maintaining a constant value of 1 over the last 5 minutes, confirming 100% availability.

Step 4: Observe Baseline Request Volume (Before Load Test)
Before generating any synthetic traffic, examine the "node_app_total_requests" panel to establish a baseline. Under normal operating conditions, the request counter should show a slow, steady increase driven only by Prometheus scrape requests and occasional organic traffic.

Figure 4: Grafana "node_app_total_requests" panel displaying the baseline metric. The counter shows approximately 333,454 to 333,476 total requests over a 5-minute window, with a gentle linear slope. This confirms the application is healthy and processing only background scrape traffic at this point.

Step 5: Generate Synthetic Load with wrk
To simulate production-level traffic, use the wrk HTTP benchmarking tool to generate a sustained burst of concurrent requests against the Node.js API:

    wrk -t8 -c500 -d120s https://poc-addweb-app.addwebprojects.com/
Enter fullscreen mode Exit fullscreen mode

This command spawns 8 threads maintaining 500 concurrent connections for 120 seconds, producing significant load on the application.

Figure 5: Terminal output of the wrk load test. Results show 203,609 total requests completed in 2 minutes at an average rate of ~1,696 requests/second. Average latency was 291.55 ms with a maximum of 956.07 ms. The 74.69 MB data transfer confirms sustained throughput throughout the test duration.

Step 6: Analyze Post-Load-Test Metrics in Grafana

After the load test completes, return to the Grafana dashboard to observe the impact. The metrics should show a dramatic spike correlating with the load test window, demonstrating that the monitoring pipeline correctly captured the traffic surge in real time.

Figure 6: Complete Grafana "Node-Application" dashboard captured during the load test. Key observations:

  • Up Status: All three services remained UP throughout the test (no downtime).
  • node_app_uptime_seconds: Uptime counter continued incrementing normally (14,200 seconds).
  • node_app_total_requests: Steep spike from 335,000 to 550,000 during the 2-minute load window.
  • grafana_alerting_request_duration_seconds_bucket: Alert evaluation latency remained stable.
  • prometheus_sd_inode_failures_total: No service discovery failures detected (flat at 0).
  • process_resident_memory_bytes: Memory usage remained stable for both Grafana (80 MB) and Prometheus (140 MB), indicating no memory leaks under load.

A closer look at the "node_app_total_requests" panel reveals the exact moment the load test began and the subsequent plateau once it completed:

Figure 7: Zoomed view of "node_app_total_requests" showing the dramatic increase from 335,000 to 540,000 during the wrk load test (approximately 17:42:30 to 17:43:30). After the test concluded, the counter flattened back to its baseline growth rate, confirming that the spike was entirely caused by the synthetic load. This panel validates that the custom prom-client Counter metric accurately tracks every HTTP request processed by the Node.js application.

Summary: The practical demonstration confirms that the Prometheus + Grafana monitoring stack is fully operational. All scrape targets are healthy, baseline metrics are collected correctly, and the system accurately reflects real-time traffic changes under load. The dashboards provide immediate visibility into application performance, making this setup suitable for production monitoring scenarios.

10. Interesting Facts & Statistics

  • Monitoring reduces MTTR by 50–60%
  • APIs without metrics often fail silently
  • Prometheus is used by thousands of production systems worldwide

11. FAQs

Q: Can I use this in production?
Yes, with persistent storage, authentication, and proper alerting.

Q: Does this support Kubernetes?
Absolutely. The same metrics approach applies to Kubernetes deployments.

Q: Can I add logs?
Yes, by integrating Grafana Loki.

12. Key Takeaways

  • Metrics are critical for API reliability
  • Prometheus is lightweight and scalable
  • Grafana simplifies observability and alerting
  • This POC closely mirrors real production setups

13. Conclusion

This practical POC demonstrates how to monitor a Node.js API end-to-end using Prometheus and Grafana.
By implementing monitoring early, teams gain better visibility, faster incident response, and improved operational stability.

About the Author: Narendra is a DevOps Engineer at AddWebSolution, specializing in automating infrastructure to improve efficiency and reliability.

Top comments (0)