← Back to blog

Monitoring Next.js with Prometheus in Kubernetes

Wiring Prometheus into a Next.js app via Server Actions and deploying the whole thing inside a Kind cluster.

#nextjs#prometheus#kubernetes#observability

Monitoring applications is essential to ensure their performance and reliability. In this tutorial, we will explore integrating Prometheus with a Next.js application using Server Actions and deploying it inside a Kind (Kubernetes in Docker) cluster. The app tracks time intervals between events and logs them as metrics Prometheus scrapes.

In this project, we:

Setting Up the Project

Clone the Repository & Install Dependencies

git clone git@github.com:mustafa-zidan/nextjs-prometheus.git
cd nextjs-prometheus
npm install

Run the Application Locally

npm run dev

Then open http://localhost:3000/

How the Next.js App Tracks Metrics

We use Server Actions in Next.js to track the time difference between pressing the Start and Stop buttons. The time elapsed is then recorded as a Prometheus metric.

import { NextRequest, NextResponse } from "next/server";
import client from "prom-client";

// Define a Prometheus Summary metric
const requestSummary = new client.Summary({
    name: "app_elapsed_time_seconds",
    help: "Time difference between start and stop tracking",
    labelNames: ["label_1", "label_2", "label_3", "label_4", "label_5", "label_6"],
});

// Register the metric if not already registered
if (!client.register.getSingleMetric("app_elapsed_time_seconds")) {
    client.register.registerMetric(requestSummary);
}

// Handle POST requests
export async function POST(req: NextRequest) {
    try {
        const body = await req.json();
        const { label_1, label_2, label_3, label_4, label_5, label_6, value } = body;

        if (!label_1 || !label_2 || !label_3 || !label_4 || !label_5 || !label_6 || typeof value !== "number") {
            return NextResponse.json({ error: "Missing or invalid parameters" }, { status: 400 });
        }

        // Record the time difference as a metric
        requestSummary.labels(label_1, label_2, label_3, label_4, label_5, label_6).observe(value);

        return NextResponse.json({ message: "Metric recorded", duration: value }, { status: 200 });
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
    } catch (error) {
        return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
    }
}

This function records the time difference as a metric that Prometheus scrapes.

Expose /api/metrics for Prometheus

Prometheus needs an endpoint to scrape data from. We expose /api/metrics using Next.js API routes:

export async function GET() {
  return new Response(await client.register.metrics(), {
    headers: { "Content-Type": client.register.contentType },
  });
}

Now, Prometheus can scrape metrics by hitting /api/metrics.

Deploying to Kubernetes (Kind)

  1. Create a Kind Cluster
kind create cluster - name monitoring-cluster
  1. Build & Deploy Next.js in Kubernetes
docker build -t nextjs-prometheus .
kind load docker-image nextjs-prometheus - name monitoring-cluster
kubectl apply -f k8s/demo.yaml
  1. Deploy Prometheus in Kubernetes
kubectl apply -f k8s/prometheus-config.yaml
kubectl apply -f k8s/prometheus-deployment.yaml
kubectl apply -f k8s/prometheus-service.yaml

Verifying Metrics in Prometheus

  1. Check Running Services
kubectl get services
kubectl get pods
  1. Expose Prometheus UI Locally
kubectl port-forward -n monitoring service/prometheus 9090:9090

Then open http://localhost:9090

  1. Query Metrics in Prometheus

  2. Go to Graph in Prometheus UI.

  3. Search for: app_elapsed_time_seconds

  4. You should see the tracked metrics from Next.js.

Conclusion

We successfully built a Next.js application with Prometheus monitoring, deployed it inside Kind Kubernetes, and verified the metrics. This setup is ideal for monitoring event-based applications that need real-time tracking.