Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 · shadcn/ui · axios · react-hook-form + zod.
Frontend for the NestJS backend at ../nestjs-starter. Handles auth (register, login, verify email, forgot/reset password) and a protected dashboard area. JWT is stored in a cookie and sent via the axios Authorization header.
- Node.js 20+
- npm 10+ (or pnpm / yarn / bun)
- The companion backend running at the URL set in
NEXT_PUBLIC_API_URL(defaults tohttp://localhost:4000/v1)
Copy .env.example to .env.local and adjust as needed:
cp .env.example .env.local| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_API_URL |
Yes | http://localhost:4000/v1 |
Base URL of the NestJS backend, including the /v1 version prefix. |
NEXT_PUBLIC_*variables are inlined into the client bundle at build time. Rebuild after changing them in production.
npm install
npm run devThe dev server runs on http://localhost:3000 with Turbopack and Fast Refresh enabled.
Useful scripts:
| Script | What it does |
|---|---|
npm run dev |
Start the dev server (next dev --turbopack). |
npm run build |
Production build (next build --turbopack). |
npm run start |
Run the production server against .next/. |
npm run lint |
Run ESLint (eslint). Do not use next lint — it's removed in Next 16. |
Type-check without emitting:
npx tsc --noEmit- Start the backend first so requests to
NEXT_PUBLIC_API_URLresolve. - Auth state lives in
AuthContext; theauth_tokencookie is the source of truth — clear it to simulate logout. - Protected routes are gated in two places:
src/proxy.ts(server-side redirect) andsrc/app/dashboard/layout.tsx(client guard). Update both when adding protected segments. - Add new typed API endpoints under
src/lib/(e.g.auth.ts,profile.ts) and import the wrappers — never call axios directly from components.
Set NEXT_PUBLIC_API_URL in your hosting platform (Vercel, Docker, systemd, etc.) to the production backend URL before running next build. Because it's a NEXT_PUBLIC_* variable, the value is baked into the client bundle and cannot be changed at runtime without rebuilding.
NEXT_PUBLIC_API_URL=https://api.example.com/v1npm ci
npm run buildnpm ci installs from package-lock.json for reproducible builds. The output is written to .next/.
npm run startBy default Next.js listens on port 3000. Override with PORT:
PORT=8080 npm run start- Vercel — zero-config. Set
NEXT_PUBLIC_API_URLin Project Settings → Environment Variables, then push. Vercel runsnext buildand serves the result. - Docker / VM — use a Node 20+ image, run
npm ci && npm run build, thennpm run start. Put a TLS-terminating reverse proxy (nginx, Caddy, ALB) in front and forwardHost,X-Forwarded-For, andX-Forwarded-Protoso Next can generate correct URLs. - Static export is not supported — this app uses client-side auth, cookies, and the Next 16 proxy (
src/proxy.ts), all of which require the Node runtime.
- Backend is reachable from the client over HTTPS at
NEXT_PUBLIC_API_URL. - Backend's CORS allowlist includes the frontend origin.
- Cookies — the
auth_tokencookie is set withSameSite=Lax. If you serve frontend and backend from different sites, make sure the backend issues cookies that the browser will accept (or rely on the existingAuthorization: Bearer …header flow, which already works cross-origin). npm run buildpasses locally with the production env vars.npx tsc --noEmitandnpm run lintare clean.- Source maps: Next 16 emits server source maps by default; review whether to upload them to your error tracker and whether to keep client source maps public.
See CLAUDE.md for the full folder layout, backend contract, error-handling conventions, and form patterns.