skip to content

Next.js

2 roadmaps170 questionsupdated

Next.js is the React meta-framework most job postings assume you already know, so interviews go straight to its App Router, rendering modes, and server-side primitives. This tree covers the Next-specific implementation of ideas React itself only sketches.

on this pageshow

guide

overview

~1 min

Next.js is the React framework that decides, for every route, where code runs — server or browser — and when its output is produced: at build time, again after a revalidation window, or per request. Interviewers probe it because those decisions surface as real bugs — stale data after a write, a whole site that quietly went dynamic, a secret that shipped to the client, an admin check that lived only in the UI. A strong answer names the file or directive behind a choice and the layer where its failure would show. The hub follows the life of a request. [Routing and layouts](/topics/fe-nextjs-routing) is the route tree that everything else hangs off. [Rendering modes](/topics/fe-nextjs-rendering) decides when each route's HTML is produced and how it streams. [Server Components](/topics/fe-nextjs-rsc) draws the line between server and browser code, and [Server Actions](/topics/fe-nextjs-server-actions) is how the browser writes back across it. [Data fetching and caching](/topics/fe-nextjs-data-caching) explains why what you see may not be what the database holds. [Middleware and API routes](/topics/fe-nextjs-middleware) covers the code that runs before a route and the endpoints outside it, and [optimization and deployment](/topics/fe-nextjs-optimization-deployment) is where images, fonts, bundles and hosting targets meet production. Junior rounds check conventions: which file makes a URL, what `'use client'` is for. Senior rounds turn into diagnosis — which cache holds the stale copy, why one call in a layout made every route dynamic, where authorization has to live when middleware already checked a cookie. Learn the route tree and the server/client split first; rendering and caching only make sense on top of them, and actions, middleware and deployment build on all three.

primer

### The filesystem is the router In the App Router, folders under `app/` are URL segments and a handful of reserved file names give a segment its behaviour: a page, a layout that wraps it, a loading state, an error boundary, an HTTP endpoint. Nesting folders nests UI, and many caching and streaming questions turn out to be about which segment the code sits in. ### Server by default, client by opt-in Components in `app/` are **Server Components**: they run on the server, can await data directly, and add nothing to the browser bundle. A `'use client'` directive marks the entry point of browser code, and everything that module imports comes along. Where that line sits decides bundle size, which props must be serializable, and what a user can read in the page source. ### A route is static until something makes it dynamic Next.js prefers to prerender. A route becomes per-request when code in any part of it — the page or any layout above it — reads something only a request can supply, such as cookies, headers or search params, or opts out explicitly. The decision belongs to the whole route, not the component that made the call, so one line in a shared layout can change the build output of a whole site. ### Caching is layered, and invalidation is your job Between a data source and the screen sit several caches, on the server and in the browser, each with its own lifetime and its own way to be cleared. A successful write says nothing about what users see next: the code that writes must tell Next.js which cached data is now wrong, by path or by tag. Good answers name the layer, not "the cache". ### Every server entry point is public Server Actions, route handlers and middleware are all reachable by anyone who can send an HTTP request, whatever the UI shows. Hiding a button, gating a URL prefix or typing a parameter enforces nothing at runtime. Validation and per-resource authorization belong in the code that reads or writes the data. ### Streaming turns waiting into structure Suspense boundaries, including the one a `loading` file creates, let the server send the parts of a page that are ready and fill in the slow parts later. Where you place a boundary and where you place an `await` decide what the user sees first.

App Router
The routing system built on the app directory, where folders define URL segments and special files define pages, layouts and states. It replaced the older pages directory as the recommended model.
Route segment
One folder level in the app directory, corresponding to one part of the URL path. Layouts, loading states and segment config attach to a segment and apply to everything beneath it.
Server Component
A React component that renders only on the server, may be async and access server resources directly, and sends rendered output rather than its code to the browser.
Client Component
A component from a module marked with the use client directive, or imported by one. It is usually prerendered on the server, then hydrated so hooks and event handlers work.
RSC payload
The serialized result of rendering Server Components: the rendered tree plus props for Client Components. Client-side navigation fetches this instead of a full HTML document.
Server Action
An async function marked with the use server directive that client code can call. Next.js exposes it as a POST endpoint, so it must validate and authorize its own input.
Static rendering
Producing a route's output ahead of any request, at build time or during revalidation, and serving the stored result to every visitor.
Dynamic rendering
Rendering a route on the server for each incoming request, needed when the output depends on who is asking or on request data such as cookies.
Incremental Static Regeneration
Serving a prerendered route and regenerating it after a staleness window or an explicit invalidation, so static pages can change without a full rebuild.
Data Cache
The persistent server-side store of fetch results, reused across requests and, depending on the host, deployments, until its entries are revalidated.
Router Cache
The in-browser memory of route segments the user has already visited or prefetched, used to make back navigation and repeat visits instant.
Partial Prerendering
A rendering model that serves a route's static shell immediately and streams its dynamic holes into it within the same response.
Middleware
A single root-level function that runs before routing for matched requests and can redirect, rewrite, or modify headers and cookies.
Route handler
A route file exporting functions named after HTTP methods, turning its folder's path into an HTTP endpoint; the App Router successor to API routes.
Edge Runtime
A lightweight JavaScript runtime exposing Web-standard APIs but not Node.js built-ins, so libraries that need the file system or raw sockets cannot run there.

Trace one request. **Middleware** runs first for any path its matcher selects and may redirect, rewrite or set headers before a route is chosen. The router then resolves the URL against the `app/` tree and composes the route: the root layout, the layouts nested beneath it, and finally the page. If the route was prerendered and its stored output is still fresh, it is served as it is; otherwise the server renders it. Rendering runs the Server Components top down, reading data through `fetch` or direct queries, each read possibly answered by the Data Cache. Where a Client Component appears, the server normally renders its HTML too and records its props in the RSC payload so the browser can hydrate it. Suspense boundaries let finished parts stream ahead of slow ones. After the first load the browser keeps the app alive. Links prefetch and navigate by fetching RSC payloads, which the Router Cache remembers. When the user submits a form wired to a **Server Action**, the action runs on the server, performs its write, and revalidates the paths or tags it touched; the response carries fresh output for the current page, and the invalidated entries are rebuilt the next time something asks for them. **Route handlers** sit beside this loop for callers that are not your own UI — webhooks, mobile clients, third parties. ```tsx // app/posts/page.tsx — a Server Component: its code never reaches the browser import { LikeButton } from './like-button' // this module starts with 'use client' export default async function Posts() { const posts = await fetch(API_URL, { next: { revalidate: 300, tags: ['posts'] } }).then(r => r.json()) return posts.map(p => <article key={p.id}>{p.title}<LikeButton id={p.id} /></article>) } // app/posts/actions.ts 'use server' export async function like(id: string) { const user = await requireUser() // authorization lives in the action await db.addLike(user.id, id) revalidatePath('/posts') // the write is not visible until a cache is told } ``` Three sections meet in those lines: the fetch options belong to caching, the `id` prop crossing into `LikeButton` is serialized into the payload, and the action is a public endpoint that must check its caller and invalidate what it changed.

  1. Routing and Layouts →

    The route tree every other section refers to: file conventions, dynamic segments, layouts and how navigation moves through them.

  2. Server Components →

    The server and client split, which decides where code runs, what reaches the bundle and what props must survive serialization.

  3. Rendering Modes →

    When a route's output is produced — build, timer or request — and how streaming shapes what appears first.

  4. Data Fetching and Caching →

    The cache layers behind stale-data bugs, and which one to invalidate; builds directly on rendering modes.

  5. Server Actions →

    The write path back to the server, where revalidation and security posture meet in one function.

  6. Middleware and API Routes →

    Code before the route and endpoints outside it, and choosing between middleware, route handlers and actions.

  • Putting 'use client' at the top of a page to make one button interactive, which drags the whole subtree into the bundle; see Composition Across the Boundary.

  • Answering a stale-data question with "clear the cache" instead of naming the layer — request memoization, Data Cache, Full Route Cache or Router Cache — and how that one is invalidated.

  • Assuming a Server Action refreshes the page's data because the write succeeded; without a path or tag revalidation the cached output stays as it was.

  • Treating a middleware cookie or role check as authorization; it gates a URL family, while per-record access must be enforced where the data is read or written.

  • Calling cookies or headers in the root layout for a small feature and discovering every route, marketing pages included, now renders per request.

  • Describing time-based revalidation as a scheduled rebuild; regeneration happens only when a request arrives after the window, and that visitor still gets the stale copy.

  • Quoting caching defaults without a version: whether a plain fetch is cached changed in Next.js 15, and many tutorials describe the older behaviour.

  • Reading a secret from process.env in a Client Component and expecting it to work; only NEXT_PUBLIC_ variables are inlined, and those are public by design.

This guide assumes the App Router on Next.js 15 or 16. Several questions turn on what changed along the way, because codebases and tutorials from earlier releases are everywhere: - **Next.js 13** introduced the `app` directory, Server Components and nested layouts; 13.4 marked the App Router stable. The `pages` directory with `getServerSideProps` and `getStaticProps` still works and is what migration questions compare against. - **Next.js 15** reversed the caching defaults: a bare `fetch` and `GET` route handlers are no longer cached unless you opt in, and request-bound APIs such as `params`, `searchParams`, `cookies()` and `headers()` became asynchronous. It also moved the App Router onto React 19. - **Next.js 16** made Turbopack the default bundler, which is why custom `webpack()` configuration questions now come with a migration angle. Explicit caching with `'use cache'` and Partial Prerendering developed across these releases behind configuration flags, so name the release and flag you mean when an answer depends on them. When an interviewer's mental model sounds like "fetch is cached by default", they are describing Next.js 13 or 14; saying so is part of a good answer.

Next.js is made by Vercel and built on React, and interviewers expect you to separate the two: Server Components and Suspense are React features, while file-system routing, the cache layers, middleware and the build pipeline are Next.js. Knowing which owns a behaviour tells you where to look when it misbehaves. It competes with other React meta-frameworks such as Remix, now continued as React Router's framework mode, which lean on web-standard loaders and actions over layered framework caching, and with Astro, which ships little or no JavaScript by default and suits content-heavy sites. Against a plain single-page app built with Vite, the trade is server infrastructure and framework rules in exchange for server rendering, smaller bundles and colocated data access. On the deployment side, Next.js runs on Vercel's managed platform, but also as a Node.js server, in a container, or as a static export when no server features are used. Some features depend on the host — image optimization, a shared cache across instances, edge execution — so a self-hosting answer should name what you now operate yourself. The [Deployment Targets](/topics/fe-nextjs-optimization-deployment-targets) section covers those choices.

explore

report an issue with this guide →

questions

170 · 7 sections

In a Next.js App Router project you create app/blog/[slug]/page.tsx. Which URLs does that one file serve, and how does the page component read the slug value?

level: juniorimportance: must knowfreq 85%
basics
~20 s

app/blog/[slug]/page.tsx serves every single-segment URL under /blog, such as /blog/hello and /blog/42. Next passes the matched text to the page in the params prop as { slug: 'hello' }; since Next 15 params is a Promise, so await it.

open as a page

In a Next.js App Router project you create the folder app/dashboard/settings/ and put a Settings.tsx component inside it, but visiting /dashboard/settings returns a 404. Why, and what actually makes a folder under app/ a routable URL?

level: juniorimportance: must knowfreq 80%
basics
~20 s

In the Next.js App Router, folders only define URL segments. A segment becomes reachable only when it contains a page file that default-exports a component (or a route file for an API endpoint). Every other file in the folder is just colocated code.

open as a page

In the Next.js App Router, what does a folder wrapped in parentheses — for example app/(marketing)/about/page.tsx — do to the resulting URL, and why would you create one?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A parenthesised folder is a route group: Next omits it from the URL, so app/(marketing)/about/page.tsx still serves /about. Groups let you organise route files and scope a layout to a subset of routes without adding a URL segment.

open as a page

In the Next.js App Router, what is special about the root layout at app/layout.tsx compared with a nested layout further down the tree?

level: juniorimportance: must knowfreq 68%
basics
~20 s

The root layout is required, wraps every route in the app, and is the only layout that renders the <html> and <body> tags. Nested layouts render plain markup inside it and apply only to their own segment and below.

open as a page

In a Next.js App Router app, what is the difference between a route that is prerendered at build time and one that is rendered on every request, in terms of when its data is read and what each visitor receives?

level: juniorimportance: must knowfreq 72%
basics
~20 s

A prerendered route fetches its data once during the production build and serves the same stored HTML to every visitor. A per-request route re-runs that code on each visit, so each visitor gets markup built from data read at that moment.

open as a page

In the Next.js App Router, a page with no special configuration is prerendered at build time. Which APIs, when a Server Component in that route calls them, switch the whole route to rendering on every request instead?

level: juniorimportance: must knowfreq 72%
basics
~10 s

Calling a Dynamic API — cookies(), headers(), draftMode() from next/headers, connection() from next/server, or reading a page's searchParams prop — opts the entire route out of prerendering, so Next.js renders it per request.

open as a page

In a Next.js App Router route segment, what does adding a loading.tsx file cause the framework to do, and which part of the UI does its output replace while data loads?

level: juniorimportance: must knowfreq 82%
basics
~20 s

Next.js wraps that segment's page.tsx and everything below it in a Suspense boundary whose fallback is loading.tsx's default export. The layout above stays on screen, and the fallback also appears instantly on client navigation into the route.

open as a page

A Next.js App Router app has three pages: a marketing landing page, a news index that must be at most a minute out of date, and a signed-in account dashboard. Which rendering mode would you choose for each, and what drives each decision?

level: middleimportance: must knowfreq 78%
basics
~20 s

Prerender the landing page at build time, give the news index a short revalidation window so it regenerates roughly every minute, and render the dashboard per request because its output depends on who is asking. The driver is whether output varies per request, then how stale it may be.

open as a page

A Next.js App Router app adds a shared header in app/layout.tsx that awaits cookies() to greet the signed-in user. After that change, every route in the build output is listed as Dynamic, including the marketing pages. Explain why one call in the layout affects unrelated pages, and how you would get those pages prerendered again.

level: middleimportance: must knowfreq 55%
basics
~20 s

Next.js decides static versus dynamic per route, and a route is the composition of the root layout plus every nested layout and the page. The root layout is part of every route, so its cookies() call opts them all out of prerendering.

open as a page

In a Next.js App Router app, a Server Component page imports a 60 kB markdown-to-HTML library and renders the result. How much of that library's JavaScript reaches the browser bundle, and what does the browser get instead?

level: juniorimportance: must knowfreq 75%
basics
~20 s

None of it. A library imported only by a Server Component runs at render time on the server, so the browser downloads zero bytes of it — only the rendered output, as HTML on the first load and as an RSC payload on client navigation.

open as a page

In the Next.js App Router, `app/orders/page.tsx` queries the database directly and awaits the result. Which pieces of the classic browser-fetch setup does that remove, and what does the browser receive instead?

level: juniorimportance: must knowfreq 76%
basics
~20 s

app/orders/page.tsx runs only on the server, so it awaits the query and renders the rows itself. The API route, the browser fetch, and the useEffect loading and error state all disappear. The browser receives rendered markup plus the RSC payload, never the query.

open as a page

In the Next.js App Router, files under app/ render on the server unless told otherwise. Which of your components actually need a 'use client' directive, and which do not?

level: juniorimportance: must knowfreq 80%
basics
~20 s

Only components that need browser behaviour: React state or effect hooks, DOM event handler props such as onClick, or browser APIs like window and localStorage. Everything else — markup, layout, data fetching — stays a Server Component with no directive.

open as a page

In a Next.js App Router app you add a client-side ThemeProvider by wrapping {children} with it inside app/layout.tsx. Does that turn every page and component below it into client code? Explain what actually happens.

level: middleimportance: must knowfreq 72%
basics
~20 s

No. Only the provider module and its own imports become client code. The pages arrive as the layout's children prop — created by the Server Component layout, rendered on the server, and handed to the provider as an already-rendered slot.

open as a page

In a Next.js App Router page, a Server Component loads a user row with 30 columns, renders the name as text, and passes only { id, name } into a Client Component. Which of that data actually reaches the browser, and how would you verify it?

level: middleimportance: must knowfreq 60%
basics
~20 s

Two things reach the browser: the markup the Server Component rendered, and a verbatim copy of the props handed to the Client Component. The other 28 columns stay on the server. Verify by searching the page source for a value you never passed.

open as a page

In a Next.js App Router app, one form is written as <form action={createTodo}> where createTodo is a Server Action, and another as <form onSubmit={handleSubmit}> whose handler calls the same Server Action. Which one still submits if the page's JavaScript never loads, and why?

level: juniorimportance: must knowfreq 52%
basics
~20 s

Only the form using the action prop still submits. Next renders it as an ordinary POST form carrying the action's identity in hidden fields, so the browser can submit it natively. An onSubmit handler cannot run until JavaScript loads and hydrates the page.

open as a page

Inside a Next.js Server Action declared as async function createUser(formData: FormData), what does formData.get('email') actually return, and why can that value not be passed straight into your database call?

level: juniorimportance: must knowfreq 62%
basics
~20 s

formData.get('email') returns FormDataEntryValue | null — a string, a File, or null if the field was absent. The FormData type annotation is erased at runtime and the body is whatever the caller posted, so the action must parse and validate before using the value.

open as a page

In the Next.js App Router, what does the 'use server' directive actually do to a function, and why is it wrong to think of it as the mirror image of 'use client'?

level: juniorimportance: must knowfreq 70%
basics
~20 s

'use server' marks a function as a server function that client code may call over the network — Next turns it into an RPC entry point. It does not make anything a Server Component; App Router components already run on the server by default.

open as a page

In a Next.js App Router app a hydrated page renders <form action={saveNote}> where saveNote is a Server Action. The user submits, the URL never changes, no fetch or setState appears anywhere in the code, and yet the page shows updated content. Walk through what actually happens between the click and the update.

level: middleimportance: must knowfreq 60%
basics
~20 s

React intercepts the submit, packs the named form controls into FormData, and POSTs it to the current URL, naming the action to run. Next executes the function on the server and returns an RSC payload that the router merges into the live page.

open as a page

In a Next.js App Router app, a Server Action can finish a write by calling either revalidatePath or revalidateTag from 'next/cache'. What does each one key on, how does data get associated with a tag, and how do you decide which to call?

level: middleimportance: must knowfreq 60%
basics
~20 s

revalidatePath keys on a route path and invalidates what that route cached; revalidateTag keys on a label you attached to the reads themselves, for example fetch(url, { next: { tags: ['posts'] } }). Use paths when you know the affected route, tags when the same data appears on many routes.

open as a page

In a Next.js App Router page.tsx, what does `export const dynamic = 'force-dynamic'` do, and when would you add it?

level: juniorimportance: must knowfreq 62%
basics
~20 s

It is a Route Segment Config export that forces the route to be rendered on the server for every request instead of being prerendered, so its HTML is never served out of Next's Full Route Cache.

open as a page

A Next.js App Router page exports `export const revalidate = 3600`. Does Next.js rebuild that page once an hour on a schedule? Explain what actually triggers the rebuild.

level: juniorimportance: must knowfreq 62%
basics
~20 s

No scheduler is involved. The number is a staleness window in seconds: after 3600 seconds the cached page is merely marked stale, and only the next incoming request for that route causes Next.js to regenerate it.

open as a page

In the Next.js App Router, what does passing `{ cache: 'force-cache' }` to `fetch` inside a Server Component do, and is that already what a plain `fetch` with no options does?

level: middleimportance: must knowfreq 78%
basics
~20 s

Passing cache: 'force-cache' stores that fetch's response in Next's server-side Data Cache so later requests reuse it instead of calling the origin. In Next 15 and 16 that is not the default: a bare fetch is uncached.

open as a page

A Next.js App Router Server Component calls `fetch(url, { next: { revalidate: 60 } })`. What exactly does that 60 apply to?

level: middleimportance: must knowfreq 66%
basics
~20 s

The 60 seconds belongs to that one Data Cache entry — the one keyed from that URL and those options — not to the component, the page, or any other fetch. Supplying it also opts the fetch into caching.

open as a page

The Next.js App Router is usually described as having four caching layers. Name them, and for each say where it physically lives and how long an entry lasts.

level: middleimportance: must knowfreq 70%
basics
~20 s

Four layers: Request Memoization (one render pass, server memory), the Data Cache (persistent server store of fetch results), the Full Route Cache (prerendered route output on the server), and the Router Cache (visited segments in browser memory for the session).

open as a page

In a Next.js App Router project, where must the middleware file live, and what does exporting `export const config = { matcher: [...] }` from it change about when the middleware function runs?

level: juniorimportance: must knowfreq 65%
basics
~20 s

Next.js reads a single middleware file at the project root, next to app/ (or inside src/). Exporting config.matcher restricts which request paths invoke it; with no matcher, the middleware function runs for every request the app serves.

open as a page

In Next.js middleware, what is the difference between returning NextResponse.rewrite(url) and NextResponse.redirect(url)?

level: juniorimportance: must knowfreq 78%
basics
~20 s

NextResponse.rewrite serves a different route internally: the browser keeps the original URL and makes one request. NextResponse.redirect returns a 3xx with a Location header, so the browser makes a second request and the address bar changes.

open as a page

In the Next.js App Router, how do you define an HTTP endpoint in a route.ts file, and what happens when a request arrives with a method the file does not export?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A route.ts file turns its folder's path into an HTTP endpoint. You export one async function per HTTP method, named exactly GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS, and Next.js answers 405 Method Not Allowed for any method you did not export.

open as a page

A Next.js App Router app can run server code in middleware.ts, in a route handler at app/api/.../route.ts, and in a Server Action marked with 'use server'. What decides which of the three a given piece of server logic belongs in?

level: middleimportance: must knowfreq 72%
basics
~20 s

Who calls the code decides. Middleware handles cross-cutting work on every matched request before routing; a route handler is a public HTTP endpoint for callers outside your app; a Server Action is an internal mutation invoked by your own UI.

open as a page

In a Next.js App Router app, do you have to configure anything for one route's JavaScript to stay out of another route's initial download, and what is next/dynamic for then?

level: juniorimportance: must knowfreq 60%
basics
~10 s

Nothing to configure: Next.js code-splits per route automatically, so visiting /dashboard does not download /settings' client code. next/dynamic splits inside a route, deferring a heavy component until it is actually rendered or needed.

open as a page

In a Next.js app, what does importing a font from `next/font/google` do that a `<link>` to fonts.googleapis.com does not — where does the browser actually fetch the font file from at runtime?

level: juniorimportance: must knowfreq 70%
basics
~20 s

next/font/google downloads the font files at build time and serves them from your own origin, so the browser never contacts Google. The build generates the @font-face CSS, and the extra DNS, TLS and stylesheet round trips disappear.

open as a page

In a Next.js App Router app, what does the `<Image>` component from `next/image` do that a plain `<img>` tag does not, and why does it refuse to render without width and height (or `fill`)?

level: juniorimportance: must knowfreq 80%
basics
~20 s

next/image generates a responsive srcset, negotiates a modern format such as WebP or AVIF, lazy-loads by default, and requires intrinsic dimensions so the browser can reserve layout space before the bytes arrive, which prevents layout shift.

open as a page

In a Next.js App Router app, what does the `ssr: false` option on `next/dynamic` change about where a component renders, and why does the build reject that option inside a Server Component?

level: middleimportance: must knowfreq 64%
basics
~20 s

With ssr: false, Next.js skips the component during server rendering and mounts it only in the browser after hydration, rendering the loading fallback in its place meanwhile. The App Router rejects the option in a Server Component because opting out of server rendering is a client-side decision.

open as a page

In a Next.js app you set `output: 'standalone'` in next.config and build a Docker image from the result. What does that build produce, and what do you have to copy into the runtime image yourself?

level: middleimportance: must knowfreq 62%
basics
~20 s

It emits a self-contained .next/standalone folder with a server.js and only the traced node_modules the server needs, so the image runs node server.js without the full project. It does not include public or .next/static — copy those in yourself.

open as a page