LearnThatStack Ace your next interview

Next.js

Next.js 16 and the App Router Checked Oct 2026 110 code snippets

The model

  • Next.js is React with a server, a router and a build step. A folder under app/ with a page.js file becomes a URL.
  • In the App Router, every component is a Server Component unless its file starts with 'use client'. Server Component code never reaches the browser.
  • The server sends HTML plus the RSC Payload, a compact description of the tree. The browser hydrates the Client Components, attaching event handlers, so their first render must match the HTML.
  • A route is static, built once by next build, until it reads request data such as cookies() or searchParams. Then it renders on every request.
  • The older Pages Router maps each file in pages/ to a URL and fetches data in getStaticProps or getServerSideProps. Both routers can run in one app.
BrowserClient ComponentsProxyproxy.js, optionalNext.js serverServer ComponentsDataDB, APIs, cacheREQUESTGET /postsnext() or rewriteRENDERawait fetch or queryRESPONDHTML + RSC Payloadclient JS hydratesACTIONServer Action POSTresult + fresh UI
One request, top to bottom. Server Components run on the server and never ship. Only Client Component code reaches the browser, where it hydrates the HTML.

App Router vs Pages Router

what Next.js adds, and its two ways to route

Routing & navigation

turn folders into URLs and move between them

Params and query strings

Read params on the serverawait params
Read params and query on the clientuseParams()useSearchParams()
Read them in the Pages Routerrouter.query
Keep a search in the URL<Form action="/search">From next/form.

Traprouter.query starts empty on a prerendered Pages Router page, so id is undefined at first.

Layouts, loading & errors

the special files that wrap each route

Layouts, templates and loading

Share UI with child pageslayout.jsKeeps state on navigation.
Reset state on every navigationtemplate.jsRemounts with a new key.
Show a loading fallbackloading.jsThe page's Suspense fallback.

TrapA layout doesn't re-render on navigation, so never rely on it alone for an auth check.

Server & Client Components

what runs where, and what can cross between them

Client Components and hydration

Make a Client Component'use client'At the top, above the imports.
Pass props from server to clientOnly serializable ones. A function can't cross.
Find why hydration failedReading window or Date in render, or a div inside a p.
Show browser-only content after hydrationuseEffect(() => setIsClient(true), [])
Let one timestamp differsuppressHydrationWarning

TrapClient Components still render to HTML on the server. 'use client' doesn't mean browser only.

Global state and saved data

Share state across pagesUse Zustand, or a Context provider in a Client Component.
Keep a theme with no flashStore it in a cookie the server can read.
Build a compound componentShare state through context, in a Client Component.

TrapA module-level store on the server is shared by all requests. Make one per request for user data.

Rendering & data fetching

when the HTML is built, and where data comes from

SSG, ISR, SSR and CSR

SSGBuild HTML once, at build time
revalidate: 60ISRRebuild static pages after deploy
SSRBuild HTML on every request
CSRBuild it in the browser
builds the HTMLdoesn't

TipSSG is fastest, but only as fresh as the last build. SSR is always fresh, but each request waits. CSR is weak for SEO.

Fetch data on the server

Fetch in the App Routerawait getPosts()In any async Server Component.
Fetch at build timegetStaticPropsAdd revalidate for ISR.
Fetch on every requestgetServerSidePropsGets req and params.

TrapgetStaticProps can't read the request. Cookies, auth and per-user data need getServerSideProps.

getStaticPaths and fallback

List the paths to prerendergetStaticPathsPair it with getStaticProps.
Return 404 for unlisted pathsfallback: false
Show a fallback page firstfallback: trueCheck router.isFallback.
Render new paths on first requestfallback: 'blocking'
List the paths in the App RoutergenerateStaticParams()

TrapNeither true nor 'blocking' updates a built page. Add revalidate for fresh content.

CMS, MDX, GraphQL and databases

Build pages from a headless CMSFetch on the server. Revalidate from its webhook.
Write pages in MDXnpm install @next/mdxAdd mdx to pageExtensions.
Reuse a database clientMake one per process. Cache it on global in dev.
Query a GraphQL APIPlain fetch on the server, Apollo on the client.

TrapRendering CMS HTML with dangerouslySetInnerHTML risks XSS. Sanitize it first.

Caching & revalidation

what Next.js keeps, and how to refresh it

Cache and revalidate data

Cache a fetch for 60 seconds{ next: { revalidate: 60 } }
Refresh a page after a writerevalidatePath(path)
Mark a tag stalerevalidateTag(tag, 'max')Refreshes in the background.
Expire a tag at onceupdateTag(tag)Only inside a Server Action.

TrapSince Next.js 15, fetch results aren't cached by default. Opt in with cache: 'force-cache'.

Cache Components and use cache

Cache a function or component'use cache'cacheLife('hours')cacheTag('posts')
Cache it before Next.js 16unstable_cache()
Serve a static shell, stream the restPartial Prerendering, part of Cache Components.

TrapCached code can't read cookies() or headers(). Read them outside and pass the values in.

API routes & Server Actions

server code that your UI or other clients call

Uploads, CORS and API errors

Accept a file uploadawait req.formData()Store it in S3, not on disk.
Accept one in pages/apibodyParser: falseThen parse with formidable.
Allow another origin with CORSSet Access-Control-Allow-* and answer OPTIONS.
Return an API errorThe right status and a JSON body, never a stack trace.

Trapfetch doesn't reject on a 404 or 500. The client must check response.ok.

Jobs, WebSockets and servers

Run code after the responseafter(() => log())
Add WebSocketsRun Socket.IO on a custom server, which Vercel can't host.
Start Next.js from your own serverapp.getRequestHandler()It can't use standalone output.
Split a domain into zonesbasePath: '/blog'

TrapNever start a queue worker in a module your routes import. It would start in every web instance.

Proxy, auth & security

guard requests, sessions and secrets

Proxy, formerly middleware

Run code before requestsproxy.jsWas middleware.js before 16.
Limit the paths it runs onmatcher: '/admin/:path*'
Redirect the requestNextResponse.redirect(url)
Run an A/B testHash a user-id cookie, then rewrite group B to its page.
Choose Edge or Node.jsUse Node.js. Edge has no filesystem and no ISR.

TrapWithout a matcher, Proxy runs on every request, static files and images included.

Styling & performance

CSS, images, fonts, bundles and Web Vitals

Lazy loading and Web Vitals

Split code by routeNext.js does it for you.
Lazy load a componentdynamic(() => import('./Chart'))
Skip server rendering{ ssr: false }Client Components only.
Improve LCP, INP and CLSPreload the hero image, ship less JavaScript, reserve space.
Report vitals from real usersuseReportWebVitals

TrapINP replaced FID as a Core Web Vital. Report INP, since web-vitals removed onFID.

Build, test & deploy

config, environment, types, tests and hosting

Turbopack, webpack and Babel

Build with webpacknext build --webpackNeeded for custom webpack.
Change the webpack configwebpack: (config) => config
Strip console.log with SWCcompiler: { removeConsole: true }

TrapA Babel config switches every file from SWC to Babel, which is about 17 times slower.

Found this useful? Pass it on.
Pro · $10/mo

This sheet stays free. With Pro, you can:

  • Every answer on this sheet. Read the full answer to all 95 questions it links, not just the 14 free ones.
  • My sheet. The cards you star and the ones you miss in Quiz me, from every sheet, on one page to quiz and print.
  • PDFs. Download this sheet and My sheet, laid out for A4, with every question a link to its answer.
  • The rest of Pro. Every answer in the question library, and 1,000 AI credits a month.