StackInterview logoStackInterview icon

Explore

Interview Qn

Interview AI

Problems

Resume Builder

Quiz

Articles

StackInterview

The complete platform to prepare for full-stack developer interviews - questions, AI mock interviews, coding practice, and guides.

Free to start

Platform

  • Interview Questions
  • Interview AI
  • Coding Problems
  • Company Tracks
  • Stack Quiz
  • JS Playground
  • Resume Builder

Guides

  • 50 Playwright Interview Questions 2026
  • Top 30 Angular Interview Questions and Answers (2026)
  • Top 25 Next.js Interview Questions and Answers (2026)
  • 50 System Design Patterns Every Engineer Should Know - 2026 Guide
  • 40+ React Hooks Interview Questions and Answers (2026)
  • View all guides →

Company

  • About Us
  • Guides & Articles
  • FAQ
  • Contact
  • Pricing
  • Privacy Policy
  • Terms of Service

© 2026 StackInterview. Built for engineers, by engineers.

PrivacyTermsContact
All Articles
🎯Interview Prep14 min read

Top 25 Next.js Interview Questions and Answers (2026)

Master Next.js 14/15 interviews: App Router, Server Components, Server Actions, Turbopack, and caching - 25 questions with code examples.

This guide covers the 25 Next.js interview questions that actually get asked at product companies in 2026 - App Router architecture, Server Components, Server Actions, caching layers, Turbopack, and production patterns - each with a concise answer and a real code snippet.

nextjsinterview-questionsapp-routerserver-componentsnextjs-2026coding-interview
On this page
  1. Top 25 Next.js Interview Questions and Answers (2026)
  2. Section 1 - Routing & Core Concepts (Q1–Q8)
  3. Q1. What is the difference between the Pages Router and the App Router?
  4. Q2. How does file-based routing work in the App Router?
  5. Q3. What are dynamic routes and catch-all routes?
  6. Q4. What is layout.tsx? How do nested layouts work?
  7. Q5. What are loading.tsx and error.tsx?
  8. Q6. What is generateStaticParams?
  9. Q7. What is generateMetadata?
  10. Q8. What are Route Groups and when do you use them?
  11. Section 2 - Server Components, Rendering & Data Fetching (Q9–Q18)
  12. Q9. What are React Server Components (RSC)?
  13. Q10. When do you use "use client"?
  14. Q11. What is the difference between SSR, SSG, ISR, and CSR?
  15. Q12. How does data fetching work in the App Router?
  16. Q13. What are Server Actions?
  17. Q14. What is the difference between revalidatePath and revalidateTag?
  18. Q15. How does Suspense work with streaming in Next.js?
  19. Q16. What are the four caching layers in the App Router?
  20. Q17. What changed in Next.js 15?
  21. Q18. What is the "use cache" directive?
  22. Section 3 - Advanced & Production (Q19–Q25)
  23. Q19. What is Next.js Middleware? Where does it run?
  24. Q20. What are Parallel Routes and Intercepting Routes?
  25. Q21. What is Turbopack?
  26. Q22. Server Actions vs Route Handlers - when do you use which?
  27. Q23. What is Partial Prerendering (PPR)?
  28. Q24. How do you implement authentication in the App Router?
  29. Q25. What are the top performance optimizations for a production Next.js app?
  30. Frequently Asked Questions
  31. Do I still need to know the Pages Router for 2026 interviews?
  32. What's the difference between useRouter from next/navigation vs next/router?
  33. When should I use a Server Component vs a Client Component?
  34. What Next.js versions should I focus on for 2026 interviews?
  35. Conclusion
Summarize with AI
ChatGPT
ChatGPT
Perplexity
Perplexity
Claude
Claude
Google AI
Google AI
Grok
Grok
Practice

Test your knowledge

Real interview questions asked at top product companies.

Practice Now
More Articles
Summarize with AI
ChatGPT
ChatGPT
Perplexity
Perplexity
Claude
Claude
Google AI
Google AI
Grok
Grok

The App Router isn't just a new folder structure. It's a fundamentally different mental model: React Server Components by default, nested layouts that don't remount, streaming with Suspense, and Server Actions that replace the need for most API endpoints. This guide covers the 25 questions that separate candidates who've read the docs from those who've shipped production App Router code.

React interview questions 2026

Key Takeaways

  • The App Router (stable since Next.js 13.4) makes every component a Server Component by default - "use client" is the opt-in, not the default

  • Next.js 15 made cookies(), headers(), params, and searchParams async - this is the most common breaking change in 2026 interviews

  • Four distinct caching layers exist in the App Router: Request Memoization, Data Cache, Full Route Cache, and Router Cache

  • Server Actions are the preferred pattern for internal mutations; Route Handlers are for external API consumers

  • Turbopack (stable in dev as of Next.js 15, production builds stable in Next.js 15.5) delivers 76.7% faster local server startup (nextjs.org/blog/next-15)


Section 1 - Routing & Core Concepts (Q1–Q8)

Routing questions come first in almost every Next.js interview. Interviewers want to know whether you understand the architectural shift the App Router represents - not just that the folder is called app/ instead of pages/.

Dark terminal window with Next.js TypeScript code and blue syntax highlighting
Dark terminal window with Next.js TypeScript code and blue syntax highlighting

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

The Pages Router treats every file in pages/ as a Client Component by default, with data fetching via getStaticProps and getServerSideProps. The App Router, stable since Next.js 13.4, makes every component in app/ a React Server Component by default, uses native async/await for data fetching, and supports nested layouts, streaming, and Server Actions.

FeaturePages RouterApp Router
Default component typeClient ComponentServer Component
Data fetchinggetStaticProps / getServerSidePropsasync component + fetch()
Layouts_app.js (re-renders on nav)layout.tsx (persists across nav)
StreamingNot supportedBuilt-in via Suspense
Server ActionsNot supported"use server" directive

Interview tip: Interviewers want the architectural shift - not just "different folder". Explain that the App Router moves data fetching to the server by default, reducing client JS bundle size and removing waterfall fetches.


Q2. How does file-based routing work in the App Router?

In the App Router, the folder structure inside app/ defines the URL structure. A page.tsx file inside any folder is the publicly accessible route for that segment. Special filenames handle specific behaviors: layout.tsx wraps child routes, loading.tsx provides a Suspense boundary, error.tsx catches render errors, and not-found.tsx renders the 404 UI.

app/
├── layout.tsx          → / (root layout, wraps everything)
├── page.tsx            → /
├── about/
│   └── page.tsx        → /about
├── blog/
│   ├── layout.tsx      → /blog (shared layout for all blog routes)
│   ├── page.tsx        → /blog
│   ├── loading.tsx     → auto Suspense fallback for /blog/*
│   ├── error.tsx       → error boundary for /blog/*
│   └── [slug]/
│       └── page.tsx    → /blog/:slug

Q3. What are dynamic routes and catch-all routes?

Dynamic route segments use brackets in folder names. [slug] matches a single segment. [...slug] matches one or more segments (catch-all). [[...slug]] matches zero or more segments (optional catch-all). In Next.js 15, params is now async and must be awaited.

// app/blog/[slug]/page.tsx
// URL: /blog/my-post → params.slug = "my-post"

interface Props {
  params: Promise<{ slug: string }>;
}

export default async function BlogPost({ params }: Props) {
  const { slug } = await params; // Next.js 15: params is async
  const post = await fetchPost(slug);
  return <article>{post.content}</article>;
}

// app/docs/[...slug]/page.tsx
// URL: /docs/a/b/c → params.slug = ["a", "b", "c"]

// app/shop/[[...filters]]/page.tsx
// URL: /shop OR /shop/shoes/red → both match

Q4. What is layout.tsx? How do nested layouts work?

A layout.tsx file wraps its sibling page.tsx and all child routes. It persists across navigations in that segment - it does not remount when a child route changes. This is the critical difference from _app.js in the Pages Router, which re-rendered on every navigation.

// app/layout.tsx - root layout (required, wraps the entire app)
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Header />
        {children}
        <Footer />
      </body>
    </html>
  );
}

// app/dashboard/layout.tsx - nested layout, only active under /dashboard/*
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="dashboard-shell">
      <Sidebar />
      <main>{children}</main>
    </div>
  );
}

Interview tip: Layouts don't rerender when the child route changes. This is what enables persistent sidebars and navigation without scroll position jumping.


Q5. What are loading.tsx and error.tsx?

loading.tsx is a shorthand for wrapping the page's content in a React boundary. Next.js renders loading.tsx immediately while the page's async data is resolving, then swaps in the real content. error.tsx is a React Error Boundary - it catches runtime errors in its segment and renders a recovery UI. It must be a Client Component.

// app/dashboard/loading.tsx - shown instantly, replaced when data resolves
export default function DashboardLoading() {
  return <DashboardSkeleton />;
}

// app/dashboard/error.tsx - catches render errors in /dashboard segment
("use client");

interface ErrorProps {
  error: Error;
  reset: () => void;
}

export default function DashboardError({ error, reset }: ErrorProps) {
  return (
    <div>
      <p>Something went wrong: {error.message}</p>
      <button onClick={reset}>Try again</button>
    </div>
  );
}

Q6. What is generateStaticParams?

generateStaticParams replaces getStaticPaths from the Pages Router. It tells Next.js which dynamic route values to pre-render at build time. Paths not returned from generateStaticParams are either rejected (with dynamicParams = false) or rendered on demand and cached.

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetchAllPosts();

  return posts.map((post) => ({
    slug: post.slug, // pre-render /blog/my-post, /blog/other-post, etc.
  }));
}

// Reject any slug not returned above
export const dynamicParams = false;

Q7. What is generateMetadata?

generateMetadata is an async function exported from any page.tsx or layout.tsx that returns a Metadata object. It replaces the component from the Pages Router. Because it's async, you can fetch data to build metadata for dynamic routes, including Open Graph and Twitter card images.

// app/blog/[slug]/page.tsx
import type { Metadata } from "next";

interface Props {
  params: Promise<{ slug: string }>;
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  const post = await fetchPost(slug);

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [{ url: post.coverImage, width: 1200, height: 630 }],
    },
  };
}

Q8. What are Route Groups and when do you use them?

Route Groups use a (groupName) folder convention. The folder name is excluded from the URL. They let you apply different layouts to routes at the same URL depth without affecting the URL structure. The most common pattern is separating a public marketing layout from a protected app layout.

app/
├── (marketing)/
│   ├── layout.tsx       → marketing layout (full-width, landing style)
│   ├── page.tsx         → /
│   └── pricing/
│       └── page.tsx     → /pricing
└── (app)/
    ├── layout.tsx       → app layout (sidebar, auth required)
    ├── dashboard/
    │   └── page.tsx     → /dashboard
    └── settings/
        └── page.tsx     → /settings

Both /pricing and /dashboard live at the same URL depth, but use completely different layouts. No URL segments are added by the route group folders.


Section 2 - Server Components, Rendering & Data Fetching (Q9–Q18)

PERSONAL EXPERIENCE -

The caching model is where most developers get tripped up when migrating from the Pages Router. In practice, we've found that understanding which of the four caching layers applies to a given bug saves hours of debugging. Interviewers at product companies specifically probe this area because it's where shallow knowledge breaks down.

Q9. What are React Server Components (RSC)?

Server Components run only on the server. They have zero JavaScript footprint in the client bundle, can directly access databases, file systems, and secrets, and render to HTML before reaching the client. In the App Router, every component is a Server Component by default unless it has a "use client" directive.

// app/products/page.tsx - Server Component, no "use client"
// This entire component runs on the server. Zero JS sent to the browser.
import { db } from "@/lib/db";

export default async function ProductsPage() {
  // Direct DB access - no API layer needed
  const products = await db.product.findMany({ take: 20 });

  return (
    <ul>
      {products.map((p) => (
        <li key={p.id}>
          <h2>{p.name}</h2>
          <p>${p.price}</p>
          {/* Client Component nested inside Server Component - valid */}
          <AddToCartButton productId={p.id} />
        </li>
      ))}
    </ul>
  );
}

Q10. When do you use "use client"?

Add "use client" to a component when it needs useState, useEffect, event handlers, or browser-only APIs (window, localStorage, etc.). It marks a boundary: everything in that file and everything it imports runs on the client. The key discipline is pushing "use client" as far down the component tree as possible to keep most of the page as Server Components.

// components/AddToCartButton.tsx
"use client";

import { useState } from "react";

interface Props {
  productId: string;
}

export function AddToCartButton({ productId }: Props) {
  const [added, setAdded] = useState(false);

  return (
    <button onClick={() => setAdded(true)}>
      {added ? "Added!" : "Add to Cart"}
    </button>
  );
}

Interview tip: The most common mistake is marking an entire page "use client" because it has one interactive button. Push the boundary to the button component itself and keep the page as a Server Component.


Q11. What is the difference between SSR, SSG, ISR, and CSR?

Each strategy determines when HTML is generated and how fresh the data is. In the App Router, you don't call different functions - you control this through fetch() options.

StrategyHTML generatedData freshnessBest for
SSG (Static)Build timeStale until redeployBlogs, docs, marketing
ISR (Incremental Static)Build time + revalidationFresh every N secondsProduct pages, listings
SSR (Dynamic)Per requestAlways freshUser dashboards, carts
CSR (Client)BrowserAlways freshHighly interactive UIs
// SSG (default) - cached indefinitely
const data = await fetch("https://api.example.com/posts");

// ISR - revalidate every 60 seconds
const data = await fetch("https://api.example.com/posts", {
  next: { revalidate: 60 },
});

// SSR - never cache, always fetch fresh
const data = await fetch("https://api.example.com/posts", {
  cache: "no-store",
});

Q12. How does data fetching work in the App Router?

Data fetching in the App Router is just await fetch() inside an async Server Component. There's no getStaticProps, no getServerSideProps. You fetch data where you need it - which means multiple components can fetch their own data in parallel without prop drilling.

// app/dashboard/page.tsx
async function getUser() {
  const res = await fetch("https://api.example.com/me", { cache: "no-store" });
  return res.json();
}

async function getStats() {
  const res = await fetch("https://api.example.com/stats", {
    next: { revalidate: 300 },
  });
  return res.json();
}

export default async function DashboardPage() {
  // Both fetches run in parallel - Next.js deduplicates identical URLs
  const [user, stats] = await Promise.all([getUser(), getStats()]);

  return (
    <div>
      <h1>Welcome, {user.name}</h1>
      <StatsGrid stats={stats} />
    </div>
  );
}

Q13. What are Server Actions?

Server Actions are async functions marked with "use server" that run on the server but can be called directly from Client Components - including from form action attributes. They're the App Router's answer to mutations: type-safe, co-located with the UI, and automatically integrated with Next.js's revalidation system. In Next.js 15, Server Actions use unguessable IDs and dead code elimination for security.

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

import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";

export async function createPost(formData: FormData) {
  const title = formData.get("title") as string;

  await db.post.create({ data: { title } });

  revalidatePath("/posts"); // bust the /posts page cache
}

// app/posts/new/page.tsx - use in a form action
import { createPost } from "../actions";

export default function NewPostPage() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Post title" required />
      <button type="submit">Create Post</button>
    </form>
  );
}

Q14. What is the difference between revalidatePath and revalidateTag?

revalidatePath purges the Full Route Cache for a specific URL. revalidateTag purges all cached fetch() calls that were tagged with a specific string, regardless of which URL they appear on. Use revalidateTag when the same data appears on multiple pages and you want a single invalidation to bust all of them.

// app/posts/page.tsx - tag the fetch so it can be invalidated by name
const data = await fetch("https://api.example.com/posts", {
  next: { tags: ["posts"] },
});
// app/posts/actions.ts - Server Action that busts all "posts"-tagged fetches
"use server";
import { revalidateTag, revalidatePath } from "next/cache";

export async function afterPostCreated() {
  revalidateTag("posts"); // busts every fetch tagged "posts" across all pages
  revalidatePath("/posts"); // also bust the /posts page shell from Full Route Cache
}

Q15. How does Suspense work with streaming in Next.js?

Next.js sends the HTML shell (layout, static parts) to the browser immediately, then streams in the content of boundaries as their async data resolves. The user sees a real page with skeleton placeholders - not a blank screen. loading.tsx is shorthand for wrapping an entire page segment in .

// app/dashboard/page.tsx - slow component wrapped in Suspense
import { Suspense } from "react";
import { RevenueChart } from "./revenue-chart";
import { RecentOrders } from "./recent-orders";

export default function DashboardPage() {
  return (
    <div>
      <h1>Dashboard</h1>
      {/* Renders immediately */}
      <Suspense fallback={<ChartSkeleton />}>
        <RevenueChart /> {/* slow DB query - streams in later */}
      </Suspense>
      <Suspense fallback={<OrdersSkeleton />}>
        <RecentOrders /> {/* independent stream - doesn't block RevenueChart */}
      </Suspense>
    </div>
  );
}

Q16. What are the four caching layers in the App Router?

Citation capsule: Next.js App Router has four distinct caching layers: Request Memoization (deduplicates identical fetch() calls within a single render pass), Data Cache (persists fetched data across requests and deployments), Full Route Cache (stores rendered HTML and RSC payload on the server), and Router Cache (stores RSC payloads client-side for prefetched and visited routes). Each layer has different storage, duration, and invalidation mechanisms (Next.js Documentation, 2025).

Cache LayerWhat it storesDurationHow to invalidate
Request Memoizationfetch() return valuesSingle requestAutomatic - per render pass
Data Cachefetch() responsesPersistent (across requests)revalidatePath, revalidateTag, no-store
Full Route CacheRendered HTML + RSC payloadPersistent (at build)Redeploy or revalidatePath
Router CacheRSC payload (client)Session (30s pages, 5min layouts)router.refresh(), Next.js 15 sets page staleTime to 0

Interview tip: Most cache-related bugs live in the Data Cache or Full Route Cache. Knowing which layer is misbehaving narrows debugging from hours to minutes.


Q17. What changed in Next.js 15?

Next.js 15 introduced breaking changes to the async Request APIs and reversed several caching defaults. Every API that reads request-time data (cookies(), headers(), params, searchParams) is now async and must be awaited. GET Route Handlers and the Router Cache for Page segments are no longer cached by default.

// BEFORE (Next.js 14)
import { cookies } from "next/headers";

export async function GET() {
  const cookieStore = cookies(); // sync - no await
  const token = cookieStore.get("token");
  return Response.json({ token });
}

// AFTER (Next.js 15) - must await
import { cookies } from "next/headers";

export async function GET() {
  const cookieStore = await cookies(); // async - await required
  const token = cookieStore.get("token");
  return Response.json({ token });
}

// params in page components also changed:
// Before: { params }: { params: { slug: string } }
// After:  { params }: { params: Promise<{ slug: string }> }
// Then:   const { slug } = await params;

Q18. What is the "use cache" directive?

"use cache" (Next.js 15 experimental, part of the dynamicIO flag) is a cache directive you can apply to any async function - not just fetch(). It lets you cache the result of a database query, an external API call, or any async computation. Use cacheTag() and cacheLife() inside the function for granular cache control. Note: the unstable_ prefix on both imports is required - these APIs haven't reached a stable interface and may change in minor versions.

// Cache any async function, not just fetch()
import {
  unstable_cacheTag as cacheTag,
  unstable_cacheLife as cacheLife,
} from "next/cache";

export async function getLatestPosts() {
  "use cache";
  cacheTag("posts");
  cacheLife("hours"); // revalidate every hour

  // This DB call is now cached like a fetch() with next.revalidate
  return await db.post.findMany({ orderBy: { createdAt: "desc" }, take: 10 });
}

Section 3 - Advanced & Production (Q19–Q25)

The questions in this section are where mid-level candidates get filtered out. Parallel Routes and Intercepting Routes are almost never covered in tutorials, but they appear frequently in senior-level interviews because they reveal whether you understand Next.js as a routing framework - not just a React wrapper. PPR and the "use cache" directive signal whether a candidate tracks the Next.js roadmap.

Q19. What is Next.js Middleware? Where does it run?

Middleware runs at the Edge Runtime - before a request hits your server, on Vercel's CDN nodes globally. It matches routes via a matcher config and can rewrite, redirect, set headers, or return a response. Common uses: authentication redirects, A/B testing, locale detection, and header injection.

// middleware.ts (project root, next to app/)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const token = request.cookies.get("auth-token");

  if (!token && request.nextUrl.pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  return NextResponse.next();
}

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

Interview tip: Middleware runs in the Edge Runtime - not Node.js. You can't use fs, crypto from Node, or most npm packages that require Node internals. Keep middleware thin: read cookies, check tokens, redirect or rewrite. Heavy logic belongs in Route Handlers or Server Actions. As of Next.js 15.5, Middleware can optionally run in the Node.js runtime via export const config = { runtime: 'nodejs' }, unlocking Node APIs - but this trades edge-CDN performance for Node.js compatibility.


Q20. What are Parallel Routes and Intercepting Routes?

Parallel Routes use @slot folders to render multiple pages in the same layout simultaneously, each with its own loading and error boundaries. A dashboard showing a main panel and a side panel - both with independent data and loading states - is the canonical example. Intercepting Routes use (.) conventions to render a route in a modal when navigated to from within the app, but as a full page on direct URL access.

// Parallel Routes: app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
  analytics, // @analytics slot
  team, // @team slot
}: {
  children: React.ReactNode;
  analytics: React.ReactNode;
  team: React.ReactNode;
}) {
  return (
    <div className="dashboard">
      {children}
      <aside>{analytics}</aside>
      <aside>{team}</aside>
    </div>
  );
}

// app/dashboard/@analytics/page.tsx - independent loading + error boundaries
// app/dashboard/@team/page.tsx - fetches its own data independently

// Intercepting Routes: app/photos/(.)photos/[id]/page.tsx
// Navigating to /photos/42 from within the app → renders modal
// Direct visit to /photos/42 URL → renders full page

Q21. What is Turbopack?

Turbopack is a Rust-based incremental bundler built by Vercel to replace Webpack in Next.js. It became stable for development in Next.js 15 and production builds became stable in Next.js 15.5. The official benchmarks from Vercel's production codebase are significant.

Citation capsule: Turbopack delivers 76.7% faster local server startup and 96.3% faster Fast Refresh on Vercel's own production codebase compared to Webpack. Next.js 15.5 extended this to production builds, delivering 2x-5x faster build times depending on project size (nextjs.org/blog/next-15, 2024).

# Enable Turbopack for dev (default in Next.js 15)
next dev --turbopack

# Production builds with Turbopack (Next.js 15.5+)
next build --turbopack

Turbopack's speed comes from incremental computation: it only re-evaluates the modules that changed, not the entire dependency graph. The architecture is similar to how build systems like Bazel track dependencies.


Q22. Server Actions vs Route Handlers - when do you use which?

Server Actions are for mutations within your own Next.js app: form submissions, button clicks, data updates. They're type-safe, co-located with your UI, and automatically handle revalidation. Route Handlers (app/api/.../route.ts) are for exposing an HTTP endpoint to external consumers: mobile apps, third-party webhooks, or any client outside your Next.js app.

// Server Action - internal mutation from a Client Component
"use server";
export async function updateProfile(data: FormData) {
  await db.user.update({
    where: { id: getSession().userId },
    data: { name: data.get("name") },
  });
  revalidatePath("/profile");
}

// Route Handler - external REST endpoint
// app/api/webhooks/stripe/route.ts
export async function POST(request: Request) {
  const event = await verifyStripeWebhook(request);
  await handleStripeEvent(event);
  return new Response("OK", { status: 200 });
}

Interview tip: Prefer Server Actions over Route Handlers for anything your own UI triggers. Route Handlers add an HTTP layer that's unnecessary for same-app mutations and can't take advantage of Next.js's integrated revalidation.


Q23. What is Partial Prerendering (PPR)?

PPR is an experimental Next.js rendering mode that combines a static HTML shell with dynamic streaming holes on a single page - served from a single request. The static shell (layout, nav, above-the-fold content) is served instantly from the CDN. Dynamic sections, defined by boundaries, stream in from the server. The goal: CDN speed for the shell, fresh data for dynamic parts.

// next.config.ts - enable PPR (experimental)
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  experimental: { ppr: true },
};

export default nextConfig;
// app/product/[id]/page.tsx - PPR page
import { Suspense } from "react";

interface Props {
  params: Promise<{ id: string }>;
}

export default async function ProductPage({ params }: Props) {
  const { id } = await params; // Next.js 15: params is async

  return (
    <div>
      <StaticHeader /> {/* in static shell - instant from CDN */}
      <Suspense fallback={<PriceSkeleton />}>
        <DynamicPrice productId={id} /> {/* dynamic hole - streams in */}
      </Suspense>
      <Suspense fallback={<ReviewsSkeleton />}>
        <UserReviews productId={id} /> {/* dynamic hole - streams in */}
      </Suspense>
    </div>
  );
}

Q24. How do you implement authentication in the App Router?

Authentication in the App Router uses three layers that each handle a different surface area. Middleware handles route protection at the edge before any server code runs. Server Components read the session to decide what to render. Server Actions handle login and logout mutations. Auth.js (formerly NextAuth) and Clerk both integrate with this three-layer pattern.

// Layer 1: Middleware - protect routes at the edge
// middleware.ts
export function middleware(request: NextRequest) {
  const session = request.cookies.get("session");
  if (!session && request.nextUrl.pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
}

// Layer 2: Server Component - read session, pass to UI
// app/dashboard/page.tsx
import { getSession } from "@/lib/auth";

export default async function DashboardPage() {
  const session = await getSession(); // reads cookies server-side
  if (!session) redirect("/login");
  return <Dashboard user={session.user} />;
}

// Layer 3: Server Action - handle logout
// app/actions/auth.ts
("use server");
import { deleteSession } from "@/lib/auth";

export async function logout() {
  await deleteSession();
  redirect("/login");
}

Q25. What are the top performance optimizations for a production Next.js app?

Production performance in Next.js comes down to six concrete patterns. Each has a measurable impact on bundle size, Core Web Vitals, or server response time.

// 1. Push "use client" to leaf components - bad vs good
// BAD: entire page becomes client bundle
"use client";
export default function ProductPage() { ... }

// GOOD: only the interactive part is a client component
export default function ProductPage() {
  return <div><StaticContent /><AddToCartButton /></div>; // AddToCartButton is "use client"
}

// 2. next/image with priority for LCP
import Image from "next/image";
<Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority />

// 3. next/font - zero layout shift from Google Fonts
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });

// 4. revalidateTag instead of cache: "no-store" everywhere
// BAD: every visit hits your DB
const data = await fetch(url, { cache: "no-store" });
// GOOD: cached, busted only when data changes
const data = await fetch(url, { next: { tags: ["products"] } });

// 5. generateStaticParams for known dynamic routes
export async function generateStaticParams() {
  return (await getTopProducts()).map((p) => ({ id: p.id }));
}

// 6. Suspense boundaries for slow data - don't block the page
<Suspense fallback={<Skeleton />}><SlowRecommendations /></Suspense>

Frequently Asked Questions

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

Yes, contextually. Companies with existing codebases - which is most companies - ask about getStaticProps, getServerSideProps, getInitialProps, and _app.js. Know them well enough to compare with App Router equivalents and explain the migration path. You won't need to write Pages Router code in a new role, but you'll inherit it.

React Hooks interview questions 2026

What's the difference between useRouter from next/navigation vs next/router?

next/navigation is the App Router package: it exports useRouter, usePathname, useSearchParams, and useParams. next/router is the Pages Router package. They're not interchangeable. Mixing them causes runtime errors. If you're in the app/ directory, always import from next/navigation.

When should I use a Server Component vs a Client Component?

Default to Server Component. Add "use client" only when you need useState, useEffect, event handlers, or browser APIs. The question to ask is: "Does this component need to respond to user interaction or browser state?" If no, keep it a Server Component. Push the "use client" boundary as far down the component tree as possible.

What Next.js versions should I focus on for 2026 interviews?

Focus on Next.js 14 and 15. From 14: stable Server Actions, the App Router caching model, and generateMetadata. From 15: async Request APIs (await cookies(), await params), reversed caching defaults (GET Route Handlers and Router Cache no longer cached by default), and Turbopack stable in dev. If the company runs Next.js 13, the concepts are the same - the APIs are nearly identical.


Conclusion

These 25 questions map the terrain from routing basics to production patterns. The App Router, Server Components, and Server Actions are the core - if you understand those three deeply, you can answer roughly 60% of what gets asked. The caching model (all four layers), the Next.js 15 breaking changes, and Turbopack's benchmarks are what separate good answers from great ones.

Work through the code examples until you can reproduce them without looking. Most interview questions that look architectural are really asking: "Can you write the code to do this?" The answer matters more than the theory.

Key Takeaways

  • App Router makes Server Components the default - "use client" is selective opt-in, not the starting point

  • Next.js 15's async Request APIs are the most tested breaking change - always await cookies(), await params

  • Know all four caching layers by name and know how to invalidate each

  • Server Actions for internal mutations, Route Handlers for external API consumers

  • Turbopack: 76.7% faster dev startup, stable for production in Next.js 15.5 (nextjs.org/blog/next-15)

Ready to broaden your prep? Senior frontend interview topics 2026 covers system design, performance, and architecture questions asked at senior and staff-level roles. For the JavaScript fundamentals that every Next.js question builds on, see JavaScript interview questions 2026 and JavaScript coding interview questions 2026.

More from Interview Prep

📚

Top 30 Angular Interview Questions and Answers (2026)

16 min read

🧪

50+ Playwright Interview Questions and Answers (2026)

22 min read

📁

Top 50 Node.js Interview Questions and Answers (2026)

22 min read

Browse All Articles