Skip to content

Review checklist

This is the checklist to run down — by eye, on any diff, yours or an AI’s — after the tools in Verification Tools have run and come back clean. It fits on one printed page on purpose: a checklist nobody actually opens during a review is worthless. Every line links to the lesson that explains why, so this page stays a list, not a re-run of the course. The groups follow the same order as How to read Next.js you did not write, plus a closing performance group.

flowchart LR
  B["Boundaries"] --> H["Mostly human review<br/>(1 real build-time check: router.push in a Server Component)"]
  A["Auth"] --> H
  E["Errors and redirects"] --> H
  D["Data and caching"] --> P["Partial tool coverage<br/>(tsc catches revalidateTag; next build catches cacheComponents conflicts)"]
  C["Config and env"] --> P
  F["Performance"] --> H
What actually catches each group, if anything
  • Does every 'use client' sit as low in the tree as it can, instead of on a shared layout or page? See Server and Client Components.
  • Does every prop crossing the Server → Client boundary stay plain data (or a genuine Server Action), with no bare class instances or unwrapped function references? See Server and Client Components.
  • Is ssr: false on next/dynamic only ever used inside a Client Component? See the AI Bug Catalog, entry 3.
  • Does useFormStatus run in a component nested inside the <form>, never the same component that renders it? See Forms and Progressive Enhancement.
  • Is every pending-state hook useActionState (from react), not the deprecated useFormState (from react-dom)? See the AI Bug Catalog, entry 5.
  • Does every useRouter/router.push call live inside a Client Component, never a Server Component? See Server and Client Components.
  • Could this data fetch run once in a Server Component instead of a client-side useEffect? See Fetching in Server Components.
  • Does next.config.ts’s cacheComponents setting match every route’s assumptions — Route Segment Config exports or 'use cache', never a mix? See Route Segment Config and Runtimes.
  • Does every fetch call state its cache intent explicitly, rather than assuming Next.js 14’s cached-by-default behavior? See The Four Caching Layers.
  • Does every revalidateTag call pass a cacheLife profile as its second argument? See Revalidation and Cache Invalidation.
  • Does a cookies()/headers() read sit inside a <Suspense> boundary, rather than at the top of a page meant to stay static? See Static and Dynamic Rendering.
  • Is every params/searchParams access awaited, and typed as a Promise rather than a loose object? See the AI Bug Catalog, entry 12.
  • Does generateStaticParams guard against ever returning an empty array under Cache Components? See the AI Bug Catalog, entry 13.
  • Has every export const runtime = 'edge' been removed, or is it a deliberate, justified exception? See Route Segment Config and Runtimes.
  • Is there a stray getServerSideProps/getStaticProps left over from the Pages Router inside app/? See What is Next.js and the App Router.
  • Does every Server Action call a real session check before touching data, independent of which UI renders the button that calls it? See What Are Server Actions?.
  • Does every mutation filter by the authenticated user’s own ID, not just confirm that someone is logged in? See Security and Patterns.
  • Does every Route Handler apply the same session check an equivalent Server Action would? See Authentication Patterns.
  • Is middleware.ts renamed to proxy.ts (and its export renamed to proxy)? See Middleware and the Request Lifecycle.
  • Is every NEXT_PUBLIC_ variable read as a static, literal process.env.NEXT_PUBLIC_X — never through a computed key or a helper function’s parameter? See the AI Bug Catalog, entry 19.
  • Does any variable prefixed NEXT_PUBLIC_ actually hold something that should be a secret? See the AI Bug Catalog, entry 20.
  • Is metadataBase set once, in the root layout? See Metadata and SEO.
  • Does every next/image using fill or a responsive layout declare sizes? See Images and Fonts.
  • Is every <a> pointing at an internal route actually a <Link>? See Linking and Navigation.
  • Does any await sit above the page’s only <Suspense> boundary, blocking the entire response? See Streaming and Suspense.
  • Does any Date.now()/Math.random() run inside a Client Component’s render — not a Server Component, where it never mismatches? See Static and Dynamic Rendering.
Why does 'does every mutation filter by the authenticated user's own ID' belong in the Auth group rather than 'Data flow and the caching model'?
Which checklist group catches this, and how?
try {
  if (!post) notFound()
  return post
} catch (err) {
  console.error(err)
  return null
}
Why does the checklist ask specifically whether params/searchParams access is 'typed as a Promise', rather than just 'awaited'?
Which group does 'is metadataBase set once in the root layout' belong to?
The checklist says to check 'does any Date.now()/Math.random() run inside a Client Component's render — not a Server Component.' Why does the distinction matter?