Dev Encyclopedia
ArticlesTools

Get notified when new content drops

No spam. Just new articles, tools, and updates straight to your inbox.

Dev Encyclopedia

A reference for builders

Content

  • Articles
  • Tools
  • Contact

Connect

  • support@devencyclopedia.com
  • RSS Feed

© 2026 Dev Encyclopedia

Privacy PolicyTermsDisclaimer
  1. Home
  2. /Blog
  3. /30 Next.js Interview Questions and Answers (2026)
nextjs22 min read

30 Next.js Interview Questions and Answers (2026)

30 Next.js interview questions with full answers: App Router, Server Components, use cache, PPR, Turbopack, and auth. Updated for Next.js 15 and 16.

By Dev EncyclopediaPublished June 8, 2026
On this page

On this page

  • Category 1: Fundamentals (Q1-Q8)
  • Q1. What is Next.js and why do companies prefer it over plain React?
  • Q2. What is the difference between the Pages Router and the App Router?
  • Q3. What rendering strategies does Next.js support?
  • Q4. What is file-based routing in Next.js?
  • Q5. How do dynamic routes work in Next.js?
  • Q6. What is generateStaticParams and when do you use it?
  • Q7. How does Next.js handle SEO?
  • Q8. What is next/image and why does it matter for performance?
  • Category 2: App Router and File Conventions (Q9-Q14)
  • Q9. What is layout.tsx and how does it differ from page.tsx?
  • Q10. What are loading.tsx and error.tsx used for?
  • Q11. How does Next.js implement nested layouts?
  • Q12. What are route groups and when would you use them?
  • Q13. What are parallel routes in Next.js?
  • Q14. What is middleware in Next.js and what changed in Next.js 16?
  • Category 3: Server Components and Client Components (Q15-Q20)
  • Q15. What is a React Server Component and how does it differ from a Client Component?
  • Q16. When should you use "use client" and when should you avoid it?
  • Q17. What causes a hydration error in Next.js and how do you fix it?
  • Q18. How do you pass data from a Server Component to a Client Component?
  • Q19. What is Suspense in the context of Next.js streaming?
  • Q20. What are Server Actions in Next.js?
  • Category 4: Data Fetching and Caching (Q21-Q26)
  • Q21. How does the "use cache" directive work in Next.js 15/16?
  • Q22. What is the difference between revalidatePath and revalidateTag?
  • Q23. What is ISR (Incremental Static Regeneration) and how does it work?
  • Q24. What is the difference between Server Actions and Route Handlers?
  • Q25. What are the four Next.js cache layers and what does each one do?
  • Q26. What are the async Request APIs introduced in Next.js 15?
  • Category 5: Performance, Deployment, and Advanced (Q27-Q30)
  • Q27. What is Partial Prerendering (PPR) and why is it significant?
  • Q28. What is Turbopack and what does it change?
  • Q29. How does next/image handle Core Web Vitals and what are its key props?
  • Q30. How would you implement authentication in a Next.js App Router project?
  • Quick Reference: All 30 Questions at a Glance
  • Frequently Asked Questions

Next.js shows up in more frontend and full-stack job postings every year, and the framework keeps moving fast enough that last year's interview prep is already out of date. The App Router, React Server Components, the use cache directive, and Partial Prerendering are all stable in Next.js 15 and 16, and interviewers are asking about them directly, not the Pages Router patterns that dominated guides written two or three years ago.

This guide collects 30 questions you are likely to be asked, grouped into five categories that roughly mirror how a real interview escalates: framework fundamentals, App Router conventions, the server/client component split, data fetching and caching, and performance plus advanced topics like PPR and Turbopack. Each answer is written the way you would actually say it out loud, not the way the docs phrase it, with code samples you can reference if you get asked to write something on a whiteboard or shared editor.

If you are setting up a fresh Next.js project to practice these concepts in, getting the tooling right first pays off. A solid Husky, Prettier, and lint-staged setup means you are not fighting formatting issues while you are trying to demo App Router patterns.

💡 How to use this guide

Skim the Quick Reference table near the bottom first to see all 30 questions and their core concept at a glance. Then jump into the categories where you feel weakest using the table of contents. Each answer ends with the kind of detail that separates a mid-level response from a senior one, the part worth rehearsing out loud.

Category 1: Fundamentals (Q1-Q8)

These are the questions that establish whether you understand what Next.js actually adds on top of React. They come up early in almost every interview, often as a warm-up before the conversation moves into App Router specifics.

Q1. What is Next.js and why do companies prefer it over plain React?

Next.js is a React framework built by Vercel that adds server-side rendering, static generation, file-based routing, image optimization, and a full caching layer on top of React. Plain React is a UI library: it handles the view layer but leaves routing, data fetching, and rendering strategy entirely to you. Next.js makes those decisions configurable rather than something you build from scratch.

Companies prefer it because it ships production-ready defaults: SEO-friendly HTML output, optimized images out of the box, automatic code splitting per route, and a deployment model that works at the edge. For content-heavy or SEO-dependent products, like e-commerce, SaaS marketing sites, and editorial platforms, the performance advantages are measurable from day one rather than something you have to engineer in later.

  • SSR, SSG, and ISR rendering strategies built directly into the framework
  • File-based routing, so there is no router configuration to maintain
  • next/image for automatic image optimization and CLS prevention
  • A built-in Metadata API for SEO
  • First-class TypeScript support out of the box

Q2. What is the difference between the Pages Router and the App Router?

The Pages Router is the original Next.js routing model, built around a /pages directory. The App Router, stable since Next.js 13.4, is the modern model built around /app, React Server Components, and a richer set of file conventions. Most production codebases still have Pages Router routes somewhere, so knowing both is expected at senior level even though new projects build on the App Router in 2026.

Pages Router (/pages)App Router (/app)
Routing conventionEvery .tsx file in /pages maps directly to a routeEvery folder containing a page.tsx becomes a route
Data fetchinggetStaticProps, getServerSideProps, getStaticPathsDirectly inside async Server Components, no special exports
Default component typeEverything is a Client Component by defaultEverything is a Server Component by default
LayoutsHandled manually in _app.tsx, easy to get wrongFirst-class layout.tsx files that persist across navigation
Where you'll see itStill common in production codebases built before 2023What new Next.js projects use in 2026

Q3. What rendering strategies does Next.js support?

Next.js supports five rendering strategies, and knowing when to reach for each one is one of the most practical signals of real-world experience an interviewer can probe for.

StrategyHow it worksBest for
SSG (Static Site Generation)HTML generated at build time and served from a CDNBlogs, docs, marketing pages: content that rarely changes
SSR (Server-Side Rendering)HTML generated on the server on every requestReal-time data, user-specific content, dashboards needing fresh data
ISR (Incremental Static Regeneration)Statically generated, then regenerated in the background on an interval or on demand via `revalidateTag`/`revalidatePath`Product pages, news feeds: content that changes occasionally but benefits from CDN speed
CSR (Client-Side Rendering)Server sends a minimal HTML shell; the browser renders via JavaScript after loadDashboards and highly interactive apps where SEO doesn't matter
PPR (Partial Prerendering)New default in Next.js 16. Mixes static and dynamic at the component level: everything outside a `<Suspense>` boundary is prerendered, everything inside streams at request timeMost production pages: CDN-speed TTFB with fresh, personalized content in the same response

Q4. What is file-based routing in Next.js?

In Next.js, the folder structure inside app/ (or pages/) directly determines the URL structure. You don't configure routes in a separate router file: the filesystem is the router.

File pathResulting route
app/page.tsx/
app/blog/page.tsx/blog
app/blog/[slug]/page.tsx/blog/:slug (dynamic segment)
app/blog/[...slug]/page.tsx/blog/a/b/c (catch-all segment)
app/(marketing)/about/page.tsx/about (route group, adds no URL segment)
app/@sidebar/page.tsxnamed parallel slot, not a standalone URL
  • Routes are discoverable just by looking at the folder structure
  • Page logic, layouts, and loading states naturally co-locate
  • Nested layouts compose automatically without extra wiring
  • There is no separate router configuration file to keep in sync with your folders

Q5. How do dynamic routes work in Next.js?

Dynamic route segments are created by wrapping a folder name in square brackets, like [slug], [id], or [category]. The detail that trips people up in 2026: starting in Next.js 15, params is a Promise, so you must await it before reading any values.

tsx — app/products/[id]/page.tsx
export default async function ProductPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params; // async since Next.js 15
  const product = await fetchProduct(id);
  return <div>{product.name}</div>;
}
  • `[slug]` — matches a single segment, e.g. /blog/my-post
  • `[...slug]` — catch-all, matches /blog/a/b/c and requires at least one segment
  • `[[...slug]]` — optional catch-all, matches both /blog and /blog/a/b/c

ℹ Info

searchParams is also a Promise in Next.js 15+. Read it the same way: const { q } = await searchParams; for query strings like ?q=value.

Q6. What is generateStaticParams and when do you use it?

generateStaticParams is the App Router equivalent of getStaticPaths from the Pages Router. It returns an array of parameter objects that Next.js uses to pre-generate static pages for a dynamic route at build time.

ts
export async function generateStaticParams() {
  const products = await fetchAllProducts();
  return products.map((p) => ({ id: p.id.toString() }));
}

Reach for it whenever you want SSG for a dynamic route: blog posts at /blog/[slug], product pages at /products/[id], documentation pages at /docs/[...path]. Without it, dynamic routes render on demand per request, which behaves like SSR. With it, Next.js pre-builds every page at deploy time and serves each one straight from a CDN. You can combine it with revalidate to get ISR behavior: static pages that quietly regenerate in the background after a set interval.

Q7. How does Next.js handle SEO?

Next.js handles SEO at several layers at once, which is exactly why it tends to outrank single-page apps built without a framework's help.

  1. Server-side HTML rendering — Server Components and SSG/SSR produce full HTML, so crawlers receive indexable content without needing to execute JavaScript.
  2. The Metadata API — export metadata (static) or generateMetadata (dynamic) from any layout.tsx or page.tsx to control title, description, Open Graph data, and more.
  3. File conventions — app/robots.ts and app/sitemap.ts generate robots.txt and sitemap.xml automatically at build time.
  4. Core Web Vitals — next/image prevents Cumulative Layout Shift and next/font eliminates font-related layout shift, both of which are direct Google ranking signals.
  5. Canonical URLs — set through metadata.alternates.canonical to avoid duplicate-content penalties.
tsx
// Static metadata
export const metadata = {
  title: "Product Name",
  description: "Under 155 characters.",
  openGraph: { title: "Product", images: ["/og.png"] },
};

// Dynamic metadata
export async function generateMetadata({ params }) {
  const product = await fetchProduct((await params).id);
  return { title: product.name };
}

Q8. What is next/image and why does it matter for performance?

next/image is a built-in component that wraps the HTML <img> tag with automatic optimization: it converts images to modern formats like WebP and AVIF (typically 20 to 40 percent smaller than JPEG), resizes images to the size they're actually rendered at, lazy-loads anything below the fold, and reserves layout space before the image loads so the page doesn't jump around as it finishes loading.

That last point is the one interviewers care about most. Cumulative Layout Shift (CLS) is a Core Web Vitals metric that directly affects Google ranking, and unoptimized images are one of the most common causes of a bad CLS score.

PropWhat it does
priorityLoads the image eagerly instead of lazily. Use it on the LCP image (hero/banner); without it, that image lazy-loads and hurts your LCP score.
fillMakes the image fill its positioned parent. Use it for responsive containers where you don't know the dimensions at compile time.
sizesTells the browser which image size to download per viewport. Critical for responsive performance, e.g. `sizes="(max-width: 768px) 100vw, 50vw"`.
qualityCompression level from 1 to 100, defaulting to 75.
altRequired. An empty string is valid for purely decorative images.

Category 2: App Router and File Conventions (Q9-Q14)

Once an interviewer knows you understand the basics, the conversation usually moves to the App Router's file conventions: layouts, loading and error states, route groups, parallel routes, and middleware. These questions test whether you've actually built something with the App Router, not just read about it.

Q9. What is layout.tsx and how does it differ from page.tsx?

page.tsx defines the unique content for a specific route. layout.tsx defines the persistent shell that wraps one or more pages. The detail that matters most: layouts do not re-render when you navigate between child routes. They stay mounted and keep their state, which is exactly why shared UI like navbars, sidebars, and tab bars belongs in a layout. It doesn't flash or reset on navigation.

app/layout.tsx is the required root layout and must include <html> and <body> tags. Inner layouts, like app/dashboard/layout.tsx, just return their children; they don't need html/body of their own.

tsx — app/dashboard/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex">
      <Sidebar />
      <main>{children}</main>
    </div>
  );
}

Q10. What are loading.tsx and error.tsx used for?

loading.tsx renders instantly while a page's async data is being fetched. Next.js automatically wraps the page in a Suspense boundary using this file as the fallback, so you get streaming with zero extra configuration: just create it alongside any page.tsx.

error.tsx catches runtime errors thrown during rendering or data fetching within its route segment, acting as a React error boundary. It must be a Client Component, since error boundaries rely on client-side lifecycle behavior, and it receives two props: error (the thrown Error object) and reset (a function to retry rendering the segment).

tsx — app/dashboard/error.tsx
"use client";

export default function Error({ error, reset }: { error: Error; reset: () => void }) {
  return (
    <div>
      <p>Something went wrong: {error.message}</p>
      <button onClick={reset}>Try again</button>
    </div>
  );
}
  • Both files are scoped to their directory: dashboard/error.tsx only catches errors from dashboard routes, not the whole app.
  • `not-found.tsx` renders when notFound() is called or a route simply doesn't exist.
  • `template.tsx` behaves like layout.tsx, except it remounts on every navigation instead of persisting.

Q11. How does Next.js implement nested layouts?

Any folder in app/ can have its own layout.tsx, and Next.js composes them automatically from outermost to innermost. For a route like /dashboard/settings, three layers stack: the root layout (app/layout.tsx), the dashboard layout (app/dashboard/layout.tsx, which provides the sidebar and top nav), and finally the page content itself.

Navigate from /dashboard/overview to /dashboard/settings and only the page content re-renders. The dashboard layout stays mounted, so the sidebar doesn't flash, and the root layout stays mounted too, so there's no full page reload. That's a meaningful UX improvement over the Pages Router, where persisting a layout meant manually engineering it inside _app.tsx.

Q12. What are route groups and when would you use them?

Route groups are folders wrapped in parentheses, like (marketing) or (auth). They let you organize routes under a shared layout without adding the folder name to the URL.

File pathResulting route
app/(marketing)/about/page.tsx/about (not /marketing/about)
app/(marketing)/pricing/page.tsx/pricing
app/(auth)/login/page.tsx/login
app/(auth)/register/page.tsx/register
  • Different layouts per section without changing URLs: (auth) pages can get a centered card layout while (app) pages get a sidebar-and-topnav layout, both serving routes at the same URL depth.
  • Organizing large codebases by grouping related routes in the filesystem for clarity, without the group name leaking into the URL.
  • Multiple root layouts: each route group can define its own layout.tsx, enabling entirely different root layouts for, say, a marketing site versus the app itself.

Q13. What are parallel routes in Next.js?

Parallel routes let you render multiple pages simultaneously within the same layout. They're defined by folders prefixed with @, like @modal or @sidebar, and these slots get passed to the parent layout as props.

tsx — app/layout.tsx
// Folder structure:
// app/
//   layout.tsx        <- receives both children and modal as props
//   page.tsx
//   @modal/
//     page.tsx        <- the parallel route content
//     default.tsx     <- rendered when the slot has no active match

export default function Layout({
  children,
  modal,
}: {
  children: React.ReactNode;
  modal: React.ReactNode;
}) {
  return (
    <>
      {children}
      {modal}
    </>
  );
}

The most common use case is intercepted route modals: clicking a photo opens it in a modal overlay while the URL changes to /photos/42, navigating directly to that URL shows the full photo page, refreshing on the modal URL shows the full page rather than the modal, and closing the modal returns you to the previous page without losing scroll position. Parallel routes combined with intercepting routes is how Next.js implements that Instagram-style modal pattern without hand-rolled client-side state management.

Q14. What is middleware in Next.js and what changed in Next.js 16?

Middleware is code that runs on every request before it reaches a page or API route, operating at the edge before any rendering happens. Typical uses include authentication redirects, role-based authorization, A/B testing rewrites, locale-based redirects for internationalization, and adding security headers to every response.

In Next.js 15 and earlier, this lived in middleware.ts at the project root. In Next.js 16, the file was renamed to proxy.ts. The reasoning: the file operates at the network proxy layer, not inside the React rendering pipeline, and the new name makes that clearer. The API itself is identical; only the filename changed.

ts — proxy.ts (Next.js 16, same API as middleware.ts)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const token = request.cookies.get("session-token");
  if (!token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*", "/account/:path*"],
};

ℹ Info

New in Next.js 16: proxy.ts can run on the Node.js and Bun runtimes in addition to the existing Edge runtime, which matters when your route protection logic needs Node.js-only APIs.

Category 3: Server Components and Client Components (Q15-Q20)

This is where interviews tend to separate candidates who have shipped App Router code from candidates who have only read about it. The server/client boundary touches everything: data fetching, bundle size, hydration, and how you structure components day to day. If your background is heavier on the React internals side, how React's renderer decides what to re-render and when is a useful companion to the questions in this section, since RSC builds directly on those same rendering primitives.

Q15. What is a React Server Component and how does it differ from a Client Component?

React Server ComponentClient Component
Where it runsExclusively on the server, never in the browserIn the browser (also pre-rendered on the server for the initial HTML)
Can it be async?Yes, it can await database queries and API calls directlyNo, but it can call functions that return promises inside effects/handlers
Hooks and browser APIsCannot use useState, useEffect, event handlers, or browser APIsFull access to React state, effects, refs, event handlers, and browser APIs
Bundle impactSends only serialized HTML to the client; adds no JS for this componentAdds JavaScript to the client bundle
How you opt inThe default for every component in the App RouterMarked explicitly with a "use client" directive at the top of the file
tsx
// Server Component — no "use client", can be async
async function ProductList() {
  const products = await db.products.findAll(); // direct DB access
  return (
    <ul>
      {products.map((p) => (
        <li key={p.id}>
          {p.name} <AddToCartButton id={p.id} /> {/* Client Component */}
        </li>
      ))}
    </ul>
  );
}

ℹ The rule that matters most

Server Components can import and render Client Components, but Client Components cannot import Server Components. Data only flows one direction, server to client, and only through serializable props. That's the entire channel.

Q16. When should you use "use client" and when should you avoid it?

Add "use client" the moment a component genuinely needs interactivity or browser access: useState, useReducer, or useContext; useEffect, useLayoutEffect, or useRef; event handlers like onClick, onChange, or onSubmit; browser APIs such as window, document, localStorage, navigator, or sessionStorage; or third-party libraries (animation, charts, drag-and-drop) that rely on any of those internally.

Avoid it when the component only fetches and displays data, receives everything it needs as props, or involves no user interaction at all. Every "use client" boundary adds JavaScript to the client bundle, and marking a purely display-oriented component as a Client Component sends unnecessary code to the browser, throws away the performance benefit of RSC, and makes the component ineligible for server-side data fetching.

The pattern that resolves almost every case: keep data fetching in a Server Component and pass the results as props to a thin Client Component that handles only the interactive part.

tsx
// Server Component — fetches data
async function ProductPage({ id }: { id: string }) {
  const product = await db.products.findById(id);
  return <AddToCartButton productId={product.id} price={product.price} />;
}

// Client Component — handles interaction only
"use client";
function AddToCartButton({ productId, price }: Props) {
  const [added, setAdded] = useState(false);
  return (
    <button onClick={() => setAdded(true)}>
      {added ? "Added!" : `Add to cart, $${price}`}
    </button>
  );
}

Q17. What causes a hydration error in Next.js and how do you fix it?

A hydration error happens when the HTML the server generated doesn't match what React renders on the client during hydration. React expects them to be identical so it can attach event listeners to the existing DOM without a full re-render; when they differ, it throws.

  1. Browser-only code running on the server — typeof window !== "undefined" checks that produce different output server-side vs. client-side. Fix: move it into useEffect, or use dynamic() with { ssr: false }.
  2. Timestamps or random values — new Date() or Math.random() resolve to different values on the server than in the browser. Fix: generate the value client-side only, inside useEffect or useMemo.
  3. Browser extensions modifying the DOM — ad blockers and password managers can alter the DOM before React hydrates. Fix: suppressHydrationWarning on the affected element; this is safe specifically because you know an external source is causing the mismatch.
  4. Invalid HTML nesting — a <p> cannot contain a <div>; browsers silently auto-correct this, which creates a mismatch. Fix: correct the HTML structure.
  5. Conditional rendering based on user state — rendering different content for logged-in vs. logged-out users on the server when you don't actually have that information at SSR time. Fix: render a neutral state on the server and update it client-side in useEffect.
tsx
// Fix for browser-only components
import dynamic from "next/dynamic";
const BrowserOnlyMap = dynamic(() => import("./Map"), { ssr: false });

Q18. How do you pass data from a Server Component to a Client Component?

You pass data as serializable props. A Server Component can fetch data and hand it to a Client Component as plain JavaScript values: strings, numbers, booleans, arrays, and plain objects.

tsx
async function ProductPage() {
  const product = await db.products.findById(id);
  // Pass serializable data as props
  return (
    <AddToCartButton
      productId={product.id}
      price={product.price}
      name={product.name}
    />
  );
}

What you cannot pass: functions (they aren't serializable across the server/client boundary), class instances, React components as values rather than JSX, anything with circular references, or symbols. Trying to pass a non-serializable value triggers a serialization error at build time or request time, so for complex shapes, convert to a plain object before handing it across.

tsx
// Bad: passing a Prisma model instance directly
return <Component product={prismaResult} />;

// Good: extract only what you need
return <Component product={{ id: prismaResult.id, name: prismaResult.name }} />;

ℹ Info

Server-only logic, like database clients, secrets, and sensitive operations, stays entirely on the server. Only the resulting data ever crosses to the client.

Q19. What is Suspense in the context of Next.js streaming?

Suspense is a React feature that shows a fallback UI while waiting for an async operation to finish. In Next.js, it's the mechanism that powers streaming Server Components.

  1. A user requests a page.
  2. Next.js immediately sends everything outside Suspense boundaries as HTML: the static shell, layout, header, footer, placeholders.
  3. Inside each Suspense boundary, Next.js sends a loading skeleton or spinner.
  4. As each Server Component resolves its data, Next.js streams the real HTML into the browser and swaps out the skeleton, all without a new request.
tsx
export default function Page() {
  return (
    <div>
      <Header />                {/* renders immediately */}
      <StaticHeroSection />     {/* renders immediately */}
      <Suspense fallback={<ProductListSkeleton />}>
        <ProductList />         {/* streams in when the DB query resolves */}
      </Suspense>
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews />             {/* streams in independently */}
      </Suspense>
    </div>
  );
}

The payoff: users see meaningful content instantly instead of a blank screen, slow data fetches don't block fast ones, and the time to first byte stays low because the server doesn't have to wait on every fetch before sending anything. loading.tsx is really just syntactic sugar for wrapping an entire page in Suspense; reach for <Suspense> directly when you want component-level control.

Q20. What are Server Actions in Next.js?

Server Actions are async functions marked with "use server" that run on the server but can be called directly from Client Components. They're designed for mutations: creating, updating, and deleting data, and they replace the older pattern of standing up a POST API route just to handle a form submission or button click.

ts — app/actions/posts.ts
"use server";

export async function createPost(formData: FormData) {
  const title = formData.get("title") as string;
  await db.posts.create({ data: { title } });
  revalidatePath("/blog");      // update cached data
  redirect("/blog");            // navigate after success
}
tsx
"use client";
import { createPost } from "../actions/posts";

export function PostForm() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Post title" />
      <button type="submit">Publish</button>
    </form>
  );
}
  • Progressive enhancement — passing a Server Action to a form's action makes the form work without JavaScript; it submits as a normal HTML form if JS fails to load.
  • Security — Server Actions are POST endpoints under the hood, and Next.js automatically adds CSRF protection. Never put sensitive logic in a Client Component; keep it inside the action.
  • After a mutation — always call revalidatePath() or revalidateTag() to clear stale cached data, or redirect() to move the user on after success.
  • `useFormStatus` / `useActionState` — the React hooks for tracking the pending and error state of a Server Action call from the client.

Category 4: Data Fetching and Caching (Q21-Q26)

Caching is where Next.js interviews tend to get genuinely hard, and for good reason: it's where the framework's behavior is least intuitive and most consequential for production bugs. These six questions cover the explicit caching model that replaced the confusing implicit fetch caching of Next.js 13/14.

Q21. How does the "use cache" directive work in Next.js 15/16?

"use cache" is an explicit caching directive introduced in Next.js 15 and stable in Next.js 16. Placing it at the top of an async function, component, or file marks its return value for server-side caching. It exists specifically to replace the implicit fetch() caching from Next.js 13/14, which left most developers unsure when results were being cached or for how long. "use cache" makes caching explicit and predictable instead.

tsx
// Cache at the function level
async function getProducts() {
  "use cache";
  cacheLife("hours");          // cache TTL profile
  cacheTag("products");        // tag for on-demand invalidation
  return await db.products.findAll();
}

// Cache at the component level
async function ProductList() {
  "use cache";
  cacheLife("minutes");
  const products = await getProducts();
  return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>;
}

// Cache at the page/file level (top of file, caches all exports)
"use cache";
export default async function BlogPage() {
  const posts = await fetchPosts();
  return <PostGrid posts={posts} />;
}
  • `cacheLife("seconds" | "minutes" | "hours" | "days" | "weeks")` sets how often the cached value revalidates.
  • `cacheTag("products", "category-electronics")` attaches one or more string tags you can later invalidate on demand with revalidateTag("products") from a Server Action.

Q22. What is the difference between revalidatePath and revalidateTag?

Both invalidate cached data and trigger a re-fetch, but at different levels of granularity. revalidatePath(path) invalidates everything cached for a specific URL path, which is the right call when a mutation only affects a single page. revalidateTag(tag) invalidates every cached entry carrying that tag, regardless of which URL it appears on, which is the right call when the same underlying data shows up across multiple pages.

ts
// After creating a new blog post, when only one page is affected:
revalidatePath("/blog");             // clears the /blog listing page
revalidatePath("/blog/my-new-post"); // clears a specific post page

// After updating a product that appears in many places:
"use server";
export async function updateProduct(id: string, data: ProductData) {
  await db.products.update({ where: { id }, data });
  revalidateTag("products");      // clears /products, /products/[id],
  revalidateTag(`product-${id}`); // homepage, and anywhere else tagged
}

💡 Tip

Default to revalidateTag for data that appears on multiple pages, and reach for revalidatePath only when you know precisely which page or pages a mutation affects. Getting this wrong in either direction either leaves stale data on screen or wipes more cache than you needed to.

Q23. What is ISR (Incremental Static Regeneration) and how does it work?

ISR lets you generate pages statically at build time and then automatically regenerate them in the background after a set interval, without a full redeploy. The flow: a page is generated statically (at build time or on first request), an incoming request gets served the cached static version instantly, and once that cache expires, Next.js triggers a background regeneration so the next request gets the freshly built version. Users never wait on the regeneration; they always get a fast static response.

tsx
// Option 1 — route segment config (whole page)
// app/blog/page.tsx
export const revalidate = 3600; // re-generate at most every hour

// Option 2 — "use cache" with cacheLife (function/component level)
async function getBlogPosts() {
  "use cache";
  cacheLife("hours"); // roughly equivalent to hourly revalidation
  return await fetchPosts();
}

// Option 3 — on-demand ISR, usually preferred in production
// In a Server Action or Route Handler, e.g. a CMS webhook:
revalidateTag("blog-posts"); // re-generates every page tagged with it,
                              // only when content actually changed

On-demand ISR via revalidateTag is generally preferred in production, because time-based ISR regenerates pages even when nothing changed, while on-demand regenerates only when your CMS or database actually has new content to serve.

Q24. What is the difference between Server Actions and Route Handlers?

Both run on the server, but they exist for different reasons.

Server ActionsRoute Handlers (app/api/.../route.ts)
Tied toThe React rendering model and your own app's UIStandard HTTP semantics: GET, POST, PUT, DELETE
Best forForm submissions, button clicks, and mutations triggered from inside your Next.js appWebhooks (Stripe, GitHub), mobile app APIs, public endpoints, third-party consumers
Form integrationPass directly to <form action={...}>; works with useFormStatus/useActionState; degrades gracefully without JSNo built-in form integration or progressive enhancement
SecurityCSRF protection handled automatically by Next.jsFull control, but you own request validation and protection yourself
Cache updatesCall revalidatePath/revalidateTag after a mutation to refresh cached dataYou manage caching headers and invalidation explicitly

ℹ The decision rule

If it's triggered by user interaction inside your own Next.js app, reach for a Server Action. If it needs to be a standard HTTP endpoint that other clients can call, build a Route Handler.

Q25. What are the four Next.js cache layers and what does each one do?

Next.js 15 and 16 ship with four distinct caching layers, and being able to explain which layer is responsible for a given behavior, and how to invalidate it, is one of the most reliable signals of senior-level mastery an interviewer can check for.

LayerScopeWhat it doesLifetime
1. Request MemoizationA single server request (one render pass)If the same async function or `fetch` call runs more than once during a single render, it executes once and the result is shared, e.g. `getUser()` called in both `layout.tsx` and `page.tsx`Cleared after each request completes
2. Data Cache ("use cache")Persistent across requests and server restartsFunctions marked `"use cache"` store their return values server-side, e.g. a product catalog cached for hours while a user session is never cachedUntil the `cacheLife` TTL expires or `revalidateTag` clears it
3. Full Route CacheServer-side, shared across all usersStatically generated HTML and RSC payloads are cached on the server and served to every visitor without re-rendering, e.g. an `/about` page served from cache to all trafficUntil the page regenerates via ISR or `revalidate`
4. Router Cache (Client Cache)Per browser session, in memoryThe browser keeps previously visited RSC payloads, so navigating back and forward is instant with no server round tripSession-based; cleared on a hard refresh

Q26. What are the async Request APIs introduced in Next.js 15?

Next.js 15 made four previously synchronous APIs asynchronous: params, searchParams, headers(), and cookies(). You now have to await all four.

tsx
// Next.js 15+ — params and searchParams are Promises
export default async function Page({
  params,
  searchParams,
}: {
  params: Promise<{ id: string }>;
  searchParams: Promise<{ q: string }>;
}) {
  const { id } = await params;
  const { q } = await searchParams;
  const cookieStore = await cookies();
  const headersList = await headers();
  // ...
}

The reasoning behind the change: accessing these synchronously meant the response had to wait until the values were available. Making them asynchronous lets Next.js start streaming the page before all of the request data has resolved, which improves both time to first byte and overall streaming performance.

⚠ This is a breaking change

It affects most existing App Router codebases. Next.js ships a codemod that updates your code automatically: npx @next/codemod@canary next-async-request-api .

Category 5: Performance, Deployment, and Advanced (Q27-Q30)

The last stretch of a Next.js interview, especially for senior roles, often turns to the newest parts of the framework: Partial Prerendering, Turbopack, deeper next/image mechanics, and how to wire up authentication correctly across the server/client boundary.

Q27. What is Partial Prerendering (PPR) and why is it significant?

PPR is a rendering strategy that removes the all-or-nothing static-versus-dynamic choice at the page level and moves it down to the component level instead. It went from experimental in Next.js 14 to the stable default in Next.js 16.

The mental model: everything outside a <Suspense> boundary is static and prerendered at build time, and everything inside one is dynamic and rendered at request time. Next.js serves the static shell from the CDN edge instantly, then streams the dynamic parts in as they resolve, all within a single HTTP response.

tsx
export default async function ProductPage() {
  return (
    <div>
      {/* Prerendered at build time, served from the CDN edge */}
      <ProductHeader />
      <ProductImages />
      <ProductDescription />

      {/* Dynamic — streamed at request time */}
      <Suspense fallback={<InventorySkeleton />}>
        <LiveInventoryStatus />          {/* real-time stock check */}
      </Suspense>
      <Suspense fallback={<RecommendationsSkeleton />}>
        <PersonalizedRecommendations />  {/* user-specific */}
      </Suspense>
    </div>
  );
}

The result is CDN-speed time to first byte (often under 50ms) for the static shell, a fast LCP because the core product information ships in that shell, and dynamic data that's still fresh and personalized. Before PPR, a single dynamic component, like a cart count, forced the entire page into SSR mode and slowed down everything on it. PPR removes that tradeoff entirely: the cart can be dynamic inside its own Suspense boundary while the rest of the page stays static.

Q28. What is Turbopack and what does it change?

Turbopack is a Rust-based JavaScript bundler built by Vercel as a modern replacement for Webpack. It was introduced as experimental in Next.js 13 (next dev --turbo), became stable and opt-in by default for next dev in Next.js 15, and became the default bundler for everything, including next build, in Next.js 16.

  • Up to 10x faster Fast Refresh (HMR) than Webpack
  • 2 to 5x faster cold builds
  • File system caching in Next.js 16, so build artifacts persist to disk and even the first startup on subsequent runs is dramatically faster
  • It's written in Rust, giving it native speed without V8 overhead
  • It replaces Webpack as the default in Next.js 16
  • Most apps need zero configuration changes; it's simply faster
  • The Webpack plugin ecosystem is the main compatibility concern, though most common plugins either have Turbopack equivalents or aren't needed at all
  • next.config.ts uses the same configuration shape for both bundlers

ℹ Info

If you depend on a Webpack plugin without a Turbopack equivalent, you can opt back into Webpack with bundler: "webpack" in next.config.ts.

Q29. How does next/image handle Core Web Vitals and what are its key props?

next/image directly addresses two Core Web Vitals metrics. For LCP (Largest Contentful Paint), the priority prop tells Next.js to preload the hero or banner image instead of lazy-loading it; skip it and your LCP image loads late, which hurts the score. For CLS (Cumulative Layout Shift), next/image requires either explicit width and height or fill, which lets the browser reserve space before the image arrives. Zero layout shift from images means zero CLS contribution from them, while plain <img> tags without dimensions are a common cause of poor CLS.

tsx
<Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority />
PropWhat it controls
priorityLoads eagerly with no lazy loading. Reserve it for the LCP image only; too many priority images defeats the purpose.
fillExpands the image to fill its positioned parent (`position: relative` required on the parent). Combine with `sizes` for the best results.
sizesTells the browser which size to download at each viewport width, e.g. `sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"`. Without it, the browser may download a 2000px image for a 300px thumbnail.
quality (default 75)Compression level from 1 to 100. Higher means better quality and a larger file; 75 is a solid default, and 60-65 works for background images.
placeholder="blur"Shows a blurred preview while the full image loads, paired with a `blurDataURL` (Next.js generates one automatically for local images). Improves perceived performance over a plain gray box.

Q30. How would you implement authentication in a Next.js App Router project?

Authentication in the App Router rests on three layers working together, and walking an interviewer through all three, in order, is usually the strongest answer you can give. If you're also handling provider keys or session secrets in the same project, it's worth pairing this with how Next.js environment variables actually reach the server versus the browser, since getting that boundary wrong is one of the most common ways auth secrets leak.

  1. Middleware / `proxy.ts` for route protection — runs on every request before any page renders. Check for a valid session cookie and redirect to /login if it's missing or invalid. This is the only reliable security layer, because it runs server-side before the user ever sees anything.
  2. Server Components for reading session state — read the session on the server with cookies() or headers(). The session token never reaches client-side JavaScript; it stays on the server the entire time.
  3. Server Actions for login, logout, and mutations — handle credential validation and cookie management inside Server Actions, never inside Client Components.
ts — proxy.ts
export async function middleware(request: NextRequest) {
  const session = request.cookies.get("session-token")?.value;
  const isValid = session ? await verifyToken(session) : false;
  if (!isValid && request.nextUrl.pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
  return NextResponse.next();
}
tsx
// In any Server Component:
const cookieStore = await cookies();
const token = cookieStore.get("session-token")?.value;
const user = token ? await getUserFromToken(token) : null;
ts
"use server";
export async function loginAction(formData: FormData) {
  const email = formData.get("email") as string;
  const password = formData.get("password") as string;
  const user = await verifyCredentials(email, password);
  if (!user) throw new Error("Invalid credentials");
  const token = await createSessionToken(user.id);
  (await cookies()).set("session-token", token, {
    httpOnly: true,    // not readable by browser JS
    secure: true,      // HTTPS only
    sameSite: "lax",   // CSRF protection
    maxAge: 60 * 60 * 24 * 7, // 7 days
  });
  redirect("/dashboard");
}
  • Auth.js (NextAuth v5) — the most popular option, with support for 50+ OAuth providers
  • Clerk — managed auth with pre-built UI components and strong developer experience
  • Lucia Auth — lightweight, with full control over the implementation
  • Kinde and WorkOS — enterprise-focused options

🚫 The point that gets candidates rejected

Never rely on client-side role checks as security. A Client Component can be inspected and modified directly in the browser. All real access control has to be enforced server-side, in middleware or in the Server Component/Action that fetches the protected data. Client-side checks exist only for UI convenience, like hiding a button or a menu item, never for actually protecting data.

Quick Reference: All 30 Questions at a Glance

Use this as a final scan the night before an interview: if any row makes you pause, jump back up to that question's full answer.

#QuestionCore concept
1What is Next.js?Framework overview
2Pages Router vs. App RouterRouting models
3Rendering strategiesSSG / SSR / ISR / CSR / PPR
4File-based routingFilesystem as router
5Dynamic routes[slug], [...slug]
6generateStaticParamsStatic param generation
7SEO in Next.jsMetadata API, RSC HTML
8next/imageImage optimization, CLS
9layout.tsx vs. page.tsxPersistent layouts
10loading.tsx and error.tsxSuspense + error boundaries
11Nested layoutsLayout composition
12Route groups(folder) organization
13Parallel routes@slot multi-panel UI
14middleware / proxy.tsRequest interception
15RSC vs. Client ComponentsServer-first rendering
16When to use "use client"Client opt-in boundary
17Hydration errorsSSR/client mismatch
18Passing data server to clientSerializable props
19Suspense and streamingProgressive rendering
20Server ActionsServer-side mutations
21"use cache" directiveExplicit caching
22revalidatePath vs. revalidateTagCache invalidation
23ISRBackground regeneration
24Server Actions vs. Route HandlersMutations vs. API
25Four cache layersFull caching model
26Async Request APIsparams, cookies, headers
27Partial Prerendering (PPR)Static shell + streaming
28TurbopackRust-based bundler
29next/image propsLCP, CLS, WebP
30AuthenticationMiddleware + Server Actions

💡 Five things to memorize before you walk in

The PPR rule (outside Suspense is static, inside is dynamic), the four cache layers in order (Request Memoization, Data Cache, Full Route Cache, Router Cache), the fact that params/searchParams/cookies()/headers() are all async since Next.js 15, that middleware.ts became proxy.ts in Next.js 16 with an identical API, and the golden auth rule: never trust client-side checks for security.

Frequently Asked Questions

How should I actually prepare for a Next.js interview, beyond memorizing answers?

Build something small with the App Router end to end, even a single CRUD feature, so you've personally hit the rough edges these questions are testing for: an async params you forgot to await, a hydration mismatch from a Date.now() call, a Server Action that needed revalidateTag to actually show its results. Interviewers can tell the difference between an answer that came from documentation and one that came from debugging your own mistake at 11pm.

After that, rehearse the answers in this guide out loud, not just read them silently. The caching questions especially (Q21, Q22, Q25) are where candidates who understand the concepts in writing still stumble when asked to explain them in real time, because the four-layer model has to come out in the right order to make sense.

Which of these 30 questions come up most often at the senior level?

The caching and rendering questions carry the most weight for senior roles: Q21 ("use cache"), Q22 (revalidatePath vs. revalidateTag), Q25 (the four cache layers), and Q27 (Partial Prerendering). These are the areas where the framework's behavior is least obvious and where a wrong answer in production costs real money in stale data or wasted compute.

Q15 and Q16, on Server Components and the "use client" boundary, are a close second. They reveal whether you actually understand why the App Router is structured the way it is, rather than just knowing the directive syntax.

Do I still need to know the Pages Router for a 2026 interview?

Yes, at least at a conceptual level. Most production Next.js codebases still have Pages Router routes somewhere, often in older parts of larger applications, and a senior-level interviewer will likely ask you to compare the two models (this guide's Q2) to see whether you can reason about migration paths and legacy code.

You don't need deep getServerSideProps mastery the way you would have in 2022. You need to recognize the patterns, explain how they map onto App Router equivalents (generateStaticParams for getStaticPaths, async Server Components for getServerSideProps), and speak credibly about why a team might migrate or choose not to.

Should I study Next.js 15 or Next.js 16 for an interview?

Both, with an emphasis on whichever the job posting or your conversation with the recruiter signals the company runs in production. Next.js 16 made Turbopack and PPR the defaults and renamed middleware.ts to proxy.ts, but the underlying APIs (the async Request APIs, "use cache", Server Actions, the four cache layers) were already stable in Next.js 15 and haven't changed in any way that matters for an interview answer.

If you're not sure which version a team is on, mention both filenames when the topic of middleware comes up (Q14). It signals that you're current without assuming the interviewer's stack matches the latest release.

If I'm asked to write code live, how much detail is expected?

Enough to show you know the shape of the API and the gotchas around it, not enough to reproduce a textbook from memory. For a dynamic route question (Q5), for example, writing the function signature with params: Promise<{ id: string }> and the await params line matters far more than getting every type annotation perfect. That single await is the detail that separates someone who has actually used Next.js 15 from someone reciting older patterns.

When you're unsure of an exact API name mid-interview, say so directly and describe what you'd reach for and why; "I'd use the cache invalidation function, I believe it's revalidateTag, to clear everything tagged with the product's ID after the mutation" reads as far stronger than confidently guessing wrong.

Related Articles

nextjs

How to Use Environment Variables in Next.js (Without Leaking Them to the Browser)

Learn how to use .env files in Next.js correctly. Understand NEXT_PUBLIC_, avoid common mistakes, and set variables in Vercel and Cloudflare.

May 30, 2026·7 min read
nextjs

Husky + Prettier + lint-staged Setup for Next.js

Set up Husky v9, Prettier, and lint-staged in your Next.js project. Step-by-step guide covering pre-commit hooks with the correct 2026 config.

May 30, 2026·8 min read
react

React Fiber Architecture Explained: How React Renders UI

React Fiber is the engine behind every React render. Learn how it works: render phase, commit phase, Lanes, and double buffering, explained with analogies.

Jun 7, 2026·12 min read

On this page

  • Category 1: Fundamentals (Q1-Q8)
  • Q1. What is Next.js and why do companies prefer it over plain React?
  • Q2. What is the difference between the Pages Router and the App Router?
  • Q3. What rendering strategies does Next.js support?
  • Q4. What is file-based routing in Next.js?
  • Q5. How do dynamic routes work in Next.js?
  • Q6. What is generateStaticParams and when do you use it?
  • Q7. How does Next.js handle SEO?
  • Q8. What is next/image and why does it matter for performance?
  • Category 2: App Router and File Conventions (Q9-Q14)
  • Q9. What is layout.tsx and how does it differ from page.tsx?
  • Q10. What are loading.tsx and error.tsx used for?
  • Q11. How does Next.js implement nested layouts?
  • Q12. What are route groups and when would you use them?
  • Q13. What are parallel routes in Next.js?
  • Q14. What is middleware in Next.js and what changed in Next.js 16?
  • Category 3: Server Components and Client Components (Q15-Q20)
  • Q15. What is a React Server Component and how does it differ from a Client Component?
  • Q16. When should you use "use client" and when should you avoid it?
  • Q17. What causes a hydration error in Next.js and how do you fix it?
  • Q18. How do you pass data from a Server Component to a Client Component?
  • Q19. What is Suspense in the context of Next.js streaming?
  • Q20. What are Server Actions in Next.js?
  • Category 4: Data Fetching and Caching (Q21-Q26)
  • Q21. How does the "use cache" directive work in Next.js 15/16?
  • Q22. What is the difference between revalidatePath and revalidateTag?
  • Q23. What is ISR (Incremental Static Regeneration) and how does it work?
  • Q24. What is the difference between Server Actions and Route Handlers?
  • Q25. What are the four Next.js cache layers and what does each one do?
  • Q26. What are the async Request APIs introduced in Next.js 15?
  • Category 5: Performance, Deployment, and Advanced (Q27-Q30)
  • Q27. What is Partial Prerendering (PPR) and why is it significant?
  • Q28. What is Turbopack and what does it change?
  • Q29. How does next/image handle Core Web Vitals and what are its key props?
  • Q30. How would you implement authentication in a Next.js App Router project?
  • Quick Reference: All 30 Questions at a Glance
  • Frequently Asked Questions