Next.js + React — Blueprint
Fullstack app with Next.js 15, React 19, and PostgreSQL
Fullstack application built with Next.js 15, React 19, and PostgreSQL. The backend exposes a JSON API; the frontend is a React client component that fetches and displays the data. Intended as a starting point for Kubernetes-deployed services: one table, one API endpoint, one page, full Docker support out of the box.
Tech stack:
| Layer | Technology |
|---|---|
| Runtime | Node.js 20 |
| Framework | Next.js 15 |
| Frontend | React 19 (client component) |
| Language | TypeScript 5 |
| Database driver | node-postgres (pg) |
| Migrations | Custom runner (plain SQL) |
The application runs on port 3000. Opening / shows the React frontend with a live connection indicator and a table of space targets.
Project Structure
app/
├── page.tsx # React client component: fetches API, renders table
├── layout.tsx # Root layout
└── api/
├── targets/route.ts # GET /api/targets
└── info/route.ts # GET /api/info
lib/
├── db.ts # pg Pool (DATABASE_URL or DB_*), sslmode handling
└── migrate.ts # Reads and runs SQL files from db/migrations/
db/migrations/
└── V1__init.sql # Creates space_target table + seed data
instrumentation.ts # Next.js hook: runs migrations on server startup
next.config.ts # output: 'standalone' for DockerKey design decisions:
app/page.tsxis a'use client'component: it runs in the browser, calls/api/infoand/api/targetsviafetch, and renders the table once both requests succeed. The connection indicator dot reflects the fetch status.lib/db.tsstripssslmodefrom the connection string before passing it topgbecause pg v8+ treatssslmode=requireasverify-full(rejecting self-signed certs). SSL is instead controlled via thesslobject, withrejectUnauthorized: falsefor cloud-managed databases.- Migrations run via Next.js
instrumentation.ts, called once when the Node.js server starts. next.config.tssetsoutput: 'standalone'for minimal Docker images. Thedb/directory is copied separately in the Dockerfile becauseinstrumentation.tsneeds the migration files at runtime.- To add a new endpoint: create a
route.tsunderapp/api/and query via the pool fromlib/db.ts. Updateapp/page.tsxto display the new data.
Environment Variables
The application runs on port 3000 and requires a PostgreSQL database.
Database connection is configured via one of two approaches:
Option A — Single connection URL (recommended for managed services)
| Variable | Required | Example |
|---|---|---|
DATABASE_URL | yes | postgres://user:pass@host:5432/dbname?sslmode=require |
Option B — Individual variables
| Variable | Required | Default | Description |
|---|---|---|---|
DB_HOST | no | localhost | Database host |
DB_PORT | no | 5432 | Database port |
DB_NAME | no | spacedb | Database name |
DB_USER | no | postgres | Database user |
DB_PASSWORD | no | postgres | Database password |
DB_SSL_MODE | no | (none) | Set to require to enable SSL |
DATABASE_URL takes precedence. If it is set, the individual DB_* variables are ignored.
Running Locally
With Docker Compose
docker compose upStarts the application together with a PostgreSQL instance and sets DATABASE_URL automatically. No additional configuration needed.
Standalone
# install dependencies
npm install
# run in development mode (DATABASE_URL or DB_* must be set)
DATABASE_URL=postgres://postgres:postgres@localhost:5432/spacedb npm run dev
# build and run in production mode
npm run build
DATABASE_URL=postgres://postgres:postgres@localhost:5432/spacedb npm start