Production-ready starter
Next.js 16.1.6
OpenTelemetry to Tempo

Lean architecture

Next.js template with tracing, metrics, and Drizzle.

Tailwind v4 and shadcn/ui for the interface, Zod and Drizzle for feature boundaries, plus structured logs, Prometheus metrics, and end-to-end tracing from request entry to database work.

Traceable routes

Request wrapper + OTEL spans from handlers into services and repositories.

Correlated logging

Pino logs carry request IDs and trace IDs so incidents can be stitched back together.

Operational metrics

Prometheus exposition with process, route, and DB metrics at /metrics.

DB visibility

Drizzle stays shallow, but repository spans still make database timing visible in Tempo.

/

Overview

What the template includes and how the pieces fit together.

Open page

/guide

Guide

How to use the project once the app is running for real work.

Open page

/operations

Operations

Runbook for health checks, metrics, logs, and tracing in production.

Open page

Next.js

16.1.6

App Router, route handlers, instrumentation, and proxy entrypoints.

Tailwind CSS

4.2.1

Tailwind v4 tokens with a light shadcn/ui layer for durable UI work.

shadcn/ui

4.0.0

Composable components kept in-repo instead of hiding logic in a package.

Zod

4.3.6

Shared contracts for env parsing, request payloads, and feature boundaries.

Drizzle ORM

0.45.1

Typed SQL access with generated migrations outside runtime source code.

OpenTelemetry

0.213.0

Root tracing, nested feature spans, and OTLP export to Grafana Tempo.

prom-client

15.1.3

Process, HTTP, and database metrics exposed at /metrics.

Vitest

4.0.18

Fast unit coverage around contracts, services, and observability helpers.

Playwright

1.58.2

Browser checks for the site, subscriber flow, and API smoke routes.

Operating model
Production-ready defaults
Lean rules that keep the template maintainable once the codebase grows.
  • Keep App Router files thin: parse the request, call a feature service, return a stable response.
  • Create spans at route, service, and repository boundaries so tracing stays useful without exploding cardinality.
  • Log with request and trace IDs by default so production incidents can be correlated quickly.
  • Prefer one shallow server layer for infra concerns instead of enterprise-style abstractions for every file.
Structure
Project layout
Folders stay shallow, but the observability pieces still have clear homes.
  • src/appRoute entrypoints, page composition, and thin HTTP adapters only.
  • src/featuresBusiness rules, validation contracts, and repositories grouped by domain.
  • src/serverEnv parsing, observability, db wiring, and generic HTTP utilities.
  • src/componentsReusable UI primitives and client components that stay close to the app.
  • drizzleGenerated SQL migrations kept outside src for cleaner runtime code.
  • opsLocal Grafana and Tempo provisioning for observability smoke tests.
Scripts
Daily commands
The command surface is small on purpose, but it still covers testing and observability.
  • pnpm checkRun linting, type checks, and unit tests in one pass.
  • pnpm e2eMigrate the local database, build the app, and run Playwright.
  • pnpm observability:upBoot Grafana and Tempo locally with ready-to-use provisioning.
  • pnpm observability:testStart the stack, run the app, and verify spans reach Tempo.
  • pnpm db:migrateApply committed migrations to the configured database.
  • pnpm devStart the local development server with the current configuration.
Example feature
Subscribers flow
The subscriber flow is a real end-to-end example that exercises validation, tracing, logging, and persistence.
Open health route

POST /api/subscribers validates input with Zod, creates spans, and persists through Drizzle.

Included baseline

Observability is part of the template, not an afterthought.

  • Structured JSON logging with request IDs and active trace IDs.
  • Prometheus-compatible metrics for Node.js, HTTP routes, and database operations.
  • OpenTelemetry spans that flow from route handlers into services and repositories.
  • Configurable ignore paths so noise like /metrics or static assets do not flood tracing.

First 15 minutes

1

Copy .env.example to .env.local and decide whether OTEL tracing should be on for your environment.

2

Run pnpm observability:up when you want Grafana Tempo available locally.

3

Run pnpm db:migrate to prepare the local SQLite database before feature work.

4

Use pnpm observability:test to verify traces, metrics, and middleware wiring end-to-end.