Next.js Roadmap

Express API · React client

The ordered build plan for a Next.js app — the full-stack alternative to the Express + React pair: nine phases from a blank idea to a monitored production deployment. One phase at a time — no phase starts before the previous deliverable exists. Estimates assume one experienced developer; solo, double them.

Next.js is not "React with extra steps" — it is a fork of the PERN decision: one deployable owning rendering, data and mutations, replacing both the Express roadmap and the React roadmap. Keep the split instead when the API must serve non-React clients, the halves ship on independent cadences, or the team is two. That decision is Phase 0 — record it.

The checkboxes are the work. This file is what actually moves the project forward.


Phase 0 — Spec (½–2 days)

Goal: a written definition of the app before any tooling.

  • One-paragraph product statement ("For [user], this app does [job], unlike [alt]")
  • Up to 10 user stories for release 1 — resist more
  • Page inventory: name + one line + rendering mode per page (server component / client island / static / dynamic) — this becomes your route table
  • SEO inventory: which routes need metadata, sitemaps, OG images, structured data — this is usually why Next.js was chosen, so measure it
  • Data model draft: entities, IDs, relationships, ownership rules
  • Non-functional requirements: auth? multi-tenant? realtime? i18n? file uploads? webhooks?
  • PERN fork recorded: Next-only (this file) vs keeping an Express API — one sentence of rationale each
  • Repo shape picked: single app (default) vs apps/web + shared package when an existing API stays

Deliverable: one page a stranger could build the route table and schema from.

Watch for: mark every page server or client in Phase 0 — "which of this is client-side?" asked in Phase 4 is a rewrite signal.

Phase 1 — Foundation (1–2 days)

Goal: an empty but correct project: builds, type-checks, lints, CI green.

  • Node 24 LTS installed (22.13+ floor); pnpm create next-app@latest with App Router, TypeScript strict, Tailwind, ESLint, src/ dir, import aliases
  • Next.js 15+ floor; App Router conventions: route groups app/(app)/, shared layouts, loading / error / not-found files
  • Env typed and validated (zod); server-only secrets (DATABASE_URL, auth secret) proven absent from client bundles
  • GET /healthz route handler that actually touches the database
  • GitHub Actions CI: lint → typecheck (tsc --noEmit) → test → next build

Deliverable: pnpm dev renders the starter; the production build is green locally and in CI.

Watch for: anything imported by a 'use client' file ends up in the browser bundle — keep secrets in server-only modules.

Phase 2 — Walking skeleton (3–5 days)

Goal: one thin slice of real value, rendered and written by the framework itself.

  • PostgreSQL 17+ (docker compose locally, managed in staging/prod) + Drizzle ORM + first migration for one entity
  • One vertical read: server component page → Drizzle query → HTML, with loading/error states designed
  • One route handler proving the programmatic path (webhooks and mobile consumers will need it)
  • One mutation via Server Action with a zod schema, revalidating the right thing by tag
  • Vitest + React Testing Library on the slice; Playwright smoke on the happy path; CI green

Deliverable: a demoable page that reads and writes one real resource, covered by tests.

Watch for: Server Actions are public HTTP endpoints — validate with zod and check auth inside the action, every time.

Phase 3 — Core capabilities (1–2 weeks)

Goal: the machinery every later page needs exists once, correctly.

  • Auth: Auth.js (NextAuth) — credentials vs OAuth decision recorded, session strategy (database vs JWT) chosen with rationale
  • Route protection at the middleware/proxy layer plus a re-check inside every protected layout and action — belt and braces
  • Design tokens + UI primitives: Button, Input, Card, List, Skeleton, Modal — same component set regardless of styling layer
  • Form pattern: react-hook-form + zod on the client, zod re-parse on the server; 422 field errors land on their fields
  • Data-access layer: one db module, query functions per aggregate — components never hand-write SQL
  • Structured logging (pino) with request IDs; Sentry wired at the framework level
  • Rate limiting on auth and abuse-prone route handlers

Deliverable: new pages become mostly composition — auth, data, validation included.

Watch for: pick the caching posture deliberately (per-route, tag-based revalidation, fully dynamic) — Next's defaults shift between majors and silent staleness is the classic incident.

Phase 4 — Feature build-out (weeks, variable)

Goal: the remaining product features, each as a vertical slice.

  • Feature per slice, server components first — 'use client' islands only where interactivity demands it
  • Mutations via Server Actions (forms) and Route Handlers (API consumers) — one validation layer serves both
  • Streaming with Suspense where data is slow; parallel fetches where data is independent
  • SEO per route: metadata API with canonical + OG per page, sitemap.xml, robots.txt, OG image generation for articles (next/og, 1200×630, text-safe)
  • File uploads presigned to object storage; webhook route handlers verify signatures and are replay-protected
  • Pagination and filter state in the URL; soft navigation UX (loading states, not spinners everywhere)

Deliverable: feature-complete against the Phase 0 spec.

Phase 5 — Quality (3–5 days + ongoing)

Goal: confidence that change does not break things.

  • Unit/component tests (Vitest + React Testing Library) on the domain-heavy parts; Server Actions tested through HTTP
  • Playwright E2E smoke: onboarding → auth → the money path, on a production build
  • Core Web Vitals budget enforced: LCP < 2.5 s, INP < 200 ms, CLS < 0.1 — numbers recorded per release
  • Lighthouse CI + bundle analyzer in CI; regressions explained, not accepted
  • Accessibility pass: axe clean + keyboard walkthrough of the money path
  • next build output reviewed whenever it jumps

Deliverable: green suite in CI + recorded performance numbers.

Phase 6 — Hardening (2–4 days)

Goal: safe to hand to strangers.

  • Boundary audit: 'use client' leakage, secrets in client bundles (grep dist/), server-only modules marked as such
  • AuthZ matrix: every page, action and route handler declares its requirement; ownership rules tested
  • Secrets out of the repo; env parity across dev/staging/prod; .env.example documents every setting
  • Headers/CSP reviewed; cookies httpOnly, Secure, SameSite
  • Dependency vulnerability scan in CI; data-shape deploys trigger the revalidation step

Deliverable: a passed checklist and a live error dashboard.

Phase 7 — Release (2–5 days)

Goal: serving production traffic.

  • Deploy target decided: Vercel first (preview deployment per PR is the default reason to pick it) vs self-hosted next start in Docker (VPC, data residency, cost ceilings) — record the reason
  • Environments wired: env vars per environment; DB migrations run as a release step, expand-contract by policy
  • OG/meta sanity checked on the deployed URL with a card validator
  • Rollback rehearsed: promote previous deployment (Vercel) or previous image (self-hosted) + migrate-forward policy
  • Smoke test: the money path runs against production after every promote

Deliverable: 1.0 serving real traffic; rollback tested.

Phase 8 — Operate & iterate (forever, ~1 h/week)

Goal: the app gets better instead of older.

  • Weekly triage: Sentry issues, Web Vitals from real users, failed builds/deploys
  • Next.js upgrades on a cadence: read the release notes, run npx @next/codemod, ship majors within a month — the framework you delay is the framework you fear
  • Quarterly: re-check the caching/revalidation posture, re-run the security checklist, revisit ADRs
  • Rotate credentials monthly-ish; glance at image/DB costs

Rules that keep this roadmap honest

  1. Walking skeleton before features. One thin end-to-end slice beats five half-built pages.
  2. No phase skips. Tests after Phase 5 are cheap; tests retrofitted in Phase 7 are not.
  3. Deliverables are binary. Each phase ends with something that exists or does not.
  4. Cut scope, not structure. A smaller feature set in a sound codebase ships; the reverse rarely does.
  5. Re-estimate at each phase boundary. The roadmap is a living document — update it as reality diverges.

Express API · React client

Built with LogoFlowershow