Next.js Roadmap
Next.js Roadmap
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@latestwith App Router, TypeScriptstrict, Tailwind, ESLint,src/dir, import aliases - Next.js 15+ floor; App Router conventions: route groups
app/(app)/, shared layouts,loading/error/not-foundfiles - Env typed and validated (zod); server-only secrets (
DATABASE_URL, auth secret) proven absent from client bundles -
GET /healthzroute 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/errorstates 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
dbmodule, 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 buildoutput 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 (grepdist/), 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.exampledocuments 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 startin 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
- Walking skeleton before features. One thin end-to-end slice beats five half-built pages.
- No phase skips. Tests after Phase 5 are cheap; tests retrofitted in Phase 7 are not.
- Deliverables are binary. Each phase ends with something that exists or does not.
- Cut scope, not structure. A smaller feature set in a sound codebase ships; the reverse rarely does.
- Re-estimate at each phase boundary. The roadmap is a living document — update it as reality diverges.