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.
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:
- Use Next.js App Router and Server Actions for metric tracking.
- Deploy the application inside a Kind Kubernetes cluster.
- Enable Prometheus to scrape metrics from our Next.js API.
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)
- Create a Kind Cluster
kind create cluster - name monitoring-cluster
- 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
- 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
- Check Running Services
kubectl get services
kubectl get pods
- Expose Prometheus UI Locally
kubectl port-forward -n monitoring service/prometheus 9090:9090
Then open http://localhost:9090
-
Query Metrics in Prometheus
-
Go to Graph in Prometheus UI.
-
Search for:
app_elapsed_time_seconds -
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.