StackInterview logoStackInterview icon

Explore

Library

Resources

Articles

Insights

StackInterview

StackInterview helps developers prepare for full-stack interviews with structured questions, real company interview insights, and modern technology coverage.

About UsFAQContactPrivacy PolicyTerms of Service

© 2026 StackInterview. Built for engineers, by engineers.

Developed and Maintained by Abhijeet Kushwaha

All Articles
⚛️React & Frontend18 min read

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

Next.js powers 9.1% of all websites. Master all 40 interview questions - App Router, Server Components, SSR/SSG/ISR, data fetching, middleware, and deployment - asked at product companies in 2026.

Next.js is the dominant React framework for production, used by 9.1% of all websites globally. This guide covers all 40 interview questions junior and mid-level developers face at product companies - from file-based routing fundamentals to App Router architecture, Server Components, caching, Server Actions, and deployment patterns - each with a concise answer and a real code snippet.

nextjsinterview-questionsreactapp-routerserver-componentsnextjs-2026coding-interview
On this page
  1. Top 40 Next.js Interview Questions and Answers (2026)
  2. Section 1 - Next.js Fundamentals (Q1–Q15)
  3. Q1. What is Next.js? How is it different from plain React?
  4. Q2. What is the difference between the Pages Router and the App Router?
  5. Q3. How does file-based routing work in Next.js App Router?
  6. Q4. What are dynamic routes? How do you create them?
  7. Q5. What is a layout in the App Router? How do nested layouts work?
  8. Q6. What are `loading.tsx` and `error.tsx` files?
  9. Q7. What is `getStaticProps`? (Pages Router)
  10. Q8. What is `getServerSideProps`? (Pages Router)
  11. Q9. What is Incremental Static Regeneration (ISR)?
  12. Q10. What is the difference between SSR, SSG, ISR, and CSR?
  13. Q11. What is `next/image`? Why should you use it?
  14. Q12. What is `next/link`? How does prefetching work?
  15. Q13. What is `next/font`? Why is it used?
  16. Q14. What are environment variables in Next.js?
  17. Q15. What is the `public` folder in Next.js?
  18. Section 2 - App Router & Rendering (Q16–Q30)
  19. Q16. What are React Server Components (RSC) in Next.js?
  20. Q17. What is the difference between Server Components and Client Components?
  21. Q18. When do you use `"use client"`?
  22. Q19. How does data fetching work in the App Router?
  23. Q20. How does Suspense work in the App Router?
  24. Q21. What is a Route Group? When would you use one?
  25. Q22. What are Parallel Routes?
  26. Q23. What are Intercepting Routes?
  27. Q24. What is the `not-found.tsx` file?
  28. Q25. What are Server Actions? How do you use them?
  29. Q26. What is `revalidatePath` vs `revalidateTag`?
  30. Q27. What is the `redirect` function in the App Router?
  31. Q28. What is `generateStaticParams`?
  32. Q29. How do you read cookies and headers inside a Server Component?
  33. Q30. What is `generateMetadata`?
  34. Section 3 - Advanced & Production (Q31–Q40)
  35. Q31. What is Next.js Middleware? Where does it run?
  36. Q32. How does the App Router caching model work?
  37. Q33. What does `cache: 'force-cache'` vs `cache: 'no-store'` do?
  38. Q34. What is Partial Prerendering (PPR)?
  39. Q35. How do you implement authentication in the App Router?
  40. Q36. What is the `use cache` directive? (Next.js 15)
  41. Q37. What is the difference between API Routes and Route Handlers?
  42. Q38. How does Next.js optimize fonts and third-party scripts?
  43. Q39. How do you deploy Next.js? What is the difference between Vercel and self-hosted?
  44. Q40. What are the most impactful Next.js performance optimizations in production?
  45. Frequently Asked Questions
  46. What Next.js version should I focus on for 2026 interviews?
  47. Do I still need to know the Pages Router for interviews?
  48. When should you use a Server Action vs an API Route Handler?
  49. How do you handle loading states in the App Router?
  50. What is the difference between `useRouter` from `next/navigation` vs `next/router`?
  51. Conclusion
Practice

Test your knowledge

Real interview questions asked at top product companies.

Practice Now
More Articles

Next.js is the dominant React framework for production - powering 9.1% of all websites globally and used by companies like Vercel, TikTok, Twitch, and Hulu (BuiltWith, 2026). That adoption converts directly into interview demand: "Next.js" is now the most commonly listed frontend framework requirement in senior web developer job postings, overtaking plain React in listings that specify a framework.

The challenge isn't finding Next.js interview content - it's finding content that actually covers the App Router. Most resources still explain the Pages Router, but every product company hiring today has either migrated to the App Router or is actively doing so. That gap is what this guide addresses.

Key Takeaways

  • Next.js App Router (introduced in v13, stable in v13.4) replaced Pages Router as the default - expect all architecture questions to focus on it

  • Server Components run on the server only; Client Components run on both server and client - understanding this split is the core App Router concept

  • Data fetching in the App Router uses native fetch with cache and next.revalidate options - no getStaticProps or getServerSideProps

  • Server Actions, Partial Prerendering, and the next/headers API are the differentiating topics at mid-to-senior levels in 2026

React interview questions 2026 → complete guide to React hooks, patterns, and modern React 18/19 features


Section 1 - Next.js Fundamentals (Q1–Q15)

Next.js was created by Vercel in 2016 and is now the most widely adopted React framework in production, powering 9.1% of all websites tracked by BuiltWith (BuiltWith, 2026). Fundamentals questions test whether you understand what Next.js adds on top of React and why it exists.

Next.js dark editor screen with React and TypeScript code syntax highlighted
Next.js dark editor screen with React and TypeScript code syntax highlighted

Q1. What is Next.js? How is it different from plain React?

Next.js is a React framework that adds server-side rendering, file-based routing, API routes, image optimization, and a build pipeline on top of React. Plain React is a UI library - it only handles the view layer. Next.js gives you a full production stack: routing, data fetching strategies (SSR/SSG/ISR), middleware, and deployment-ready output out of the box.

// Plain React: you own routing, server, data fetching, bundling
import { createRoot } from "react-dom/client";
createRoot(document.getElementById("root")).render(<App />);

// Next.js: file system = routes, server = built-in, data fetching = built-in
// app/page.tsx → renders at "/"
export default function HomePage() {
  return <h1>Hello from Next.js</h1>;
}

Interview tip: Interviewers ask this to check if you understand why "React developer" and "Next.js developer" are meaningfully different skills. Lead with the server-rendering and routing story.


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

The Pages Router (/pages directory) is Next.js's original routing system. Data fetching happens via getStaticProps, getServerSideProps, and getStaticPaths. The App Router (/app directory), stable since Next.js 13.4, is built on React Server Components. Data fetching uses native async/await with fetch. Layouts are composable, nested, and persistent - they don't unmount on navigation.

FeaturePages RouterApp Router
Default component typeClient ComponentServer Component
Data fetchinggetStaticProps / getServerSidePropsasync component + fetch
Layouts_app.js (single, global)layout.tsx (nested, composable)
StreamingNot supportedBuilt-in via Suspense
Server ActionsNot supportedBuilt-in

Interview tip: If you learned Next.js before v13, walk through this table explicitly - interviewers want to know you understand the architectural shift, not just that the router changed.


Q3. How does file-based routing work in Next.js App Router?

In the App Router, the folder structure under /app defines the URL structure. Every folder becomes a route segment. A page.tsx file inside a folder makes that route publicly accessible. A layout.tsx wraps child routes. Special files (loading.tsx, error.tsx, not-found.tsx) activate automatically for their respective UI states.

app/
├── page.tsx            → /
├── layout.tsx          → root layout (always rendered)
├── about/
│   └── page.tsx        → /about
├── blog/
│   ├── page.tsx        → /blog
│   └── [slug]/
│       └── page.tsx    → /blog/:slug (dynamic)
└── dashboard/
    ├── layout.tsx      → persistent layout for /dashboard/*
    └── page.tsx        → /dashboard

Q4. What are dynamic routes? How do you create them?

A folder wrapped in square brackets ([slug]) creates a dynamic route segment. The param is passed to the page.tsx as params.slug. For catch-all routes, use [...slug] (matches /a/b/c). For optional catch-all, use [[...slug]] (also matches the base path /).

// app/blog/[slug]/page.tsx
interface Props {
  params: { slug: string };
}

export default function BlogPost({ params }: Props) {
  return <h1>Post: {params.slug}</h1>;
}

// For /blog/my-first-post → params.slug = "my-first-post"

Q5. What is a layout in the App Router? How do nested layouts work?

A layout.tsx file wraps all pages within its folder and below. Layouts persist across navigations - they don't remount when the user moves between child routes. Nested layouts stack: the root app/layout.tsx wraps everything; a app/dashboard/layout.tsx wraps only dashboard routes, rendered inside the root layout's {children}.

// app/layout.tsx - root layout, wraps every page
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Navbar /> {/* always visible */}
        {children} {/* page or nested layout renders here */}
        <Footer />
      </body>
    </html>
  );
}

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

Q6. What are `loading.tsx` and `error.tsx` files?

loading.tsx automatically wraps a route's page in a boundary. Next.js streams the layout immediately and shows the loading UI while the page's data resolves - no manual Suspense needed. error.tsx is a React Error Boundary that catches runtime errors in its route segment and renders a fallback UI.

// app/dashboard/loading.tsx - shown while dashboard/page.tsx data loads
export default function Loading() {
  return <div className="skeleton-screen" aria-label="Loading dashboard..." />;
}

// app/dashboard/error.tsx - catches errors in the dashboard segment
("use client"); // error boundaries must be Client Components
export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div>
      <h2>Something went wrong</h2>
      <button onClick={reset}>Try again</button>
    </div>
  );
}

Q7. What is `getStaticProps`? (Pages Router)

getStaticProps runs at build time on the server and passes data as props to the page component. The page is pre-rendered as static HTML. It's the Pages Router equivalent of a Server Component that fetches data - but it only runs once at build time (or on revalidation with ISR).

// pages/blog/[slug].tsx
export async function getStaticProps({ params }) {
  const post = await fetchPost(params.slug);
  return { props: { post }, revalidate: 60 }; // ISR: regenerate every 60s
}

export default function BlogPost({ post }) {
  return <article>{post.content}</article>;
}

Interview tip: In the App Router, getStaticProps doesn't exist. The equivalent is an async Server Component with fetch(..., { next: { revalidate: 60 } }).


Q8. What is `getServerSideProps`? (Pages Router)

getServerSideProps runs on the server on every request. It has access to the request context (cookies, headers) and returns props to the page. It's the Pages Router equivalent of SSR - the page is never cached as static HTML.

// pages/profile.tsx
export async function getServerSideProps({ req }) {
  const token = req.cookies.authToken;
  if (!token) return { redirect: { destination: "/login", permanent: false } };
  const user = await getUser(token);
  return { props: { user } };
}

export default function Profile({ user }) {
  return <h1>Hello, {user.name}</h1>;
}

App Router equivalent: async Server Component that calls cookies() from next/headers.


Q9. What is Incremental Static Regeneration (ISR)?

ISR lets a statically generated page regenerate in the background after a set interval without a full rebuild. After the revalidation window passes, the next request triggers a background regeneration - the stale page is served until the new one is ready. This gives you the performance of static pages with the freshness of server-rendered ones.

// Pages Router - via revalidate in getStaticProps
export async function getStaticProps() {
  const data = await fetchProducts();
  return { props: { data }, revalidate: 300 }; // regenerate every 5 minutes
}

// App Router - via fetch option
async function ProductList() {
  const data = await fetch("https://api.example.com/products", {
    next: { revalidate: 300 }, // same 5-minute ISR behavior
  }).then((r) => r.json());
  return (
    <ul>
      {data.map((p) => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  );
}

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

StrategyWhen HTML is generatedData freshnessBest for
SSG (Static)Build timeStale until rebuildBlogs, docs, marketing pages
ISRBuild + background refreshFresh within revalidate windowProduct catalogs, news
SSREvery requestAlways freshAuth-gated pages, personalized content
CSRIn the browserOn fetchDashboards, real-time data

In the App Router, SSG is the default (cached indefinitely), ISR uses revalidate, SSR uses cache: 'no-store', and CSR uses Client Components with useEffect / SWR / React Query.


Q11. What is `next/image`? Why should you use it?

next/image is Next.js's built-in component. It automatically lazy-loads images, serves modern formats (WebP, AVIF), resizes images on-demand via a built-in optimization API, and prevents Cumulative Layout Shift (CLS) by requiring width and height (or fill). Using raw tags skips all of this.

import Image from "next/image";

// Prevents CLS, lazy-loads, serves WebP automatically
<Image
  src="/hero.jpg"
  alt="Dashboard screenshot showing analytics data"
  width={1200}
  height={630}
  priority // eager-load for above-the-fold images (LCP element)
/>;

Interview tip: Mention priority on LCP images - it's a common follow-up about Core Web Vitals.


Q12. What is `next/link`? How does prefetching work?

next/link renders an tag that navigates client-side without a full page reload. It prefetches the linked page's JavaScript bundle when the link enters the viewport (in production builds). This makes navigation feel instant because the code is already loaded before the user clicks.

import Link from "next/link";

function Nav() {
  return (
    <nav>
      <Link href="/">Home</Link>
      {/* Prefetched when visible in viewport (production only) */}
      <Link href="/blog" prefetch={false}>
        Blog
      </Link>
      {/* prefetch={false} disables prefetching - useful for low-traffic routes */}
    </nav>
  );
}

Q13. What is `next/font`? Why is it used?

next/font downloads Google Fonts (or local fonts) at build time and serves them self-hosted, eliminating the external network request to Google's CDN. It automatically applies font-display: swap, removes layout shift, and inlines the CSS - all without any runtime JavaScript.

import { Inter } from "next/font/google";

const inter = Inter({
  subsets: ["latin"],
  display: "swap",
});

export default function RootLayout({ children }) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

Q14. What are environment variables in Next.js?

Next.js loads .env.local automatically. Variables prefixed with NEXTPUBLIC are exposed to the browser bundle. All other variables remain server-only. Never put secrets in NEXTPUBLIC variables - they're baked into the client JavaScript.

# .env.local
DATABASE_URL=postgresql://...       # server-only (never in client bundle)
NEXT_PUBLIC_API_URL=https://api.example.com  # exposed to browser
// Server Component or API route - can read DATABASE_URL
const db = process.env.DATABASE_URL;

// Client Component - can only read NEXT_PUBLIC_ variables
const apiUrl = process.env.NEXT_PUBLIC_API_URL;

Q15. What is the `public` folder in Next.js?

Files inside /public are served as-is at the root URL. A file at /public/logo.png is accessible at https://yoursite.com/logo.png. Next.js doesn't process or optimize these files (use next/image for images that need optimization). The public folder is ideal for robots.txt, sitemap.xml, favicon files, and other static assets.


Section 2 - App Router & Rendering (Q16–Q30)

The App Router is the biggest architectural shift in Next.js history. Built on React Server Components, it changes where code runs, how data is fetched, and how layouts compose. These questions are the ones most candidates stumble on in 2026 because most study guides haven't caught up.

PERSONAL EXPERIENCE - Every mid-level Next.js interview I've seen in the last year pivots to App Router concepts within the first ten minutes. Candidates who only know getStaticProps/getServerSideProps get filtered out fast - not because Pages Router knowledge is wrong, but because it signals they haven't worked with a production App Router codebase.

Terminal showing Next.js build output with Server Components and route optimization statistics
Terminal showing Next.js build output with Server Components and route optimization statistics

Q16. What are React Server Components (RSC) in Next.js?

React Server Components run exclusively on the server - they never ship JavaScript to the client. They can directly access databases, file systems, and secrets. They render to HTML (or a special wire format) and send the result to the browser. In the App Router, every component is a Server Component by default unless you add "use client".

// app/users/page.tsx - Server Component (default, no "use client")
// This code NEVER runs in the browser
import { db } from "@/lib/db";

export default async function UsersPage() {
  const users = await db.query("SELECT * FROM users"); // direct DB access ✅
  return (
    <ul>
      {users.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}

Q17. What is the difference between Server Components and Client Components?

Server Components run only on the server - no event handlers, no hooks, no browser APIs. They're zero-bundle-size for the client and can access server resources directly. Client Components (marked "use client") run on both the server (for initial HTML) and the client (for interactivity). They can use hooks, event handlers, and browser APIs.

Server ComponentClient Component
Runs onServer onlyServer + client
Can use hooksNoYes
Can use event handlersNoYes
Can access DB/secretsYesNo
Adds to JS bundleNoYes
Default in App RouterYesNo ("use client" required)

Q18. When do you use `"use client"`?

Add "use client" to a component when it needs: event handlers (onClick, onChange), React hooks (useState, useEffect, useRef), browser APIs (window, localStorage, navigator), or third-party libraries that use any of the above. The directive marks a boundary - everything imported below that boundary becomes a Client Component too.

"use client";

import { useState } from "react";

// This component needs state → must be a Client Component
export default function LikeButton({ initialCount }: { initialCount: number }) {
  const [count, setCount] = useState(initialCount);
  return <button onClick={() => setCount((c) => c + 1)}>♥ {count}</button>;
}

Interview tip: The mistake candidates make is marking entire page-level components as "use client" just because one small piece needs interactivity. Push interactivity down to a leaf component instead - the rest of the tree stays server-rendered.


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

Server Components can be async functions. You await data directly inside the component body - no getStaticProps, no useEffect, no loading state required. Next.js extends the native fetch with cache and next.revalidate options to control whether the data is static, ISR, or always-fresh.

// app/blog/page.tsx - async Server Component
export default async function BlogPage() {
  // Static (default) - cached indefinitely, like getStaticProps
  const posts = await fetch("https://api.example.com/posts").then((r) =>
    r.json(),
  );

  // ISR - revalidate every 60 seconds
  const featured = await fetch("https://api.example.com/featured", {
    next: { revalidate: 60 },
  }).then((r) => r.json());

  // SSR - never cached, always fresh
  const live = await fetch("https://api.example.com/live", {
    cache: "no-store",
  }).then((r) => r.json());

  return <BlogList posts={posts} featured={featured} live={live} />;
}

Q20. How does Suspense work in the App Router?

boundaries let Next.js stream HTML progressively. Content outside the boundary is sent immediately; content inside is streamed when its data resolves. Wrapping slow data fetches in Suspense prevents them from blocking the entire page - the layout and fast sections render first, then slow sections stream in.

import { Suspense } from "react";
import { Skeleton } from "@/components/ui";

// RecentActivity fetches slowly - don't block the whole page
export default function Dashboard() {
  return (
    <div>
      <WelcomeBanner /> {/* renders immediately */}
      <Suspense fallback={<Skeleton />}>
        <RecentActivity /> {/* streams in when data resolves */}
      </Suspense>
    </div>
  );
}

// async Server Component - suspends automatically while fetching
async function RecentActivity() {
  const activity = await fetchActivity(); // slow query
  return <ActivityFeed data={activity} />;
}

Q21. What is a Route Group? When would you use one?

A folder wrapped in parentheses - (groupName) - creates a Route Group. It organizes routes without affecting the URL path. Use it to: apply different layouts to routes at the same URL depth, or separate marketing pages from app pages without changing their URLs.

app/
├── (marketing)/
│   ├── layout.tsx      → layout for marketing pages only
│   ├── page.tsx        → /
│   └── about/
│       └── page.tsx    → /about (not /(marketing)/about)
└── (app)/
    ├── layout.tsx      → layout for app pages (auth-gated)
    └── dashboard/
        └── page.tsx    → /dashboard

Q22. What are Parallel Routes?

Parallel Routes render multiple pages simultaneously in the same layout using named slots (@slotName folders). Each slot gets its own loading.tsx, error.tsx, and independent navigation state. Common use case: a dashboard with an @analytics and @notifications slot that both load independently.

app/dashboard/
├── layout.tsx          → receives @analytics and @notifications as props
├── page.tsx            → default slot content
├── @analytics/
│   └── page.tsx        → rendered in the "analytics" slot
└── @notifications/
    └── page.tsx        → rendered in the "notifications" slot
// app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
  analytics,
  notifications,
}: {
  children: React.ReactNode;
  analytics: React.ReactNode;
  notifications: React.ReactNode;
}) {
  return (
    <div className="grid grid-cols-3">
      <main>{children}</main>
      <aside>{analytics}</aside>
      <aside>{notifications}</aside>
    </div>
  );
}

Q23. What are Intercepting Routes?

Intercepting Routes let you load a route within a different layout context while the URL changes. The classic example: clicking a photo in a feed opens it in a modal (intercepted route), but navigating directly to its URL shows the full photo page. Use (.), (..), (..)(..), or (...) prefixes to intercept at different depths.

app/
├── feed/
│   └── page.tsx            → /feed (shows photo grid)
└── (.)photos/
    └── [id]/
        └── page.tsx        → intercepts /photos/:id when navigating from /feed
                              (shows modal); navigating directly shows full page

Q24. What is the `not-found.tsx` file?

not-found.tsx renders when notFound() is called from anywhere in its route segment, or when no route matches a URL under it. It replaces the default Next.js 404 page. Placing one at app/not-found.tsx sets the global 404; placing one inside a segment makes it segment-specific.

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

export default async function BlogPost({
  params,
}: {
  params: { slug: string };
}) {
  const post = await fetchPost(params.slug);
  if (!post) notFound(); // triggers app/blog/not-found.tsx (or app/not-found.tsx)
  return <article>{post.content}</article>;
}

// app/not-found.tsx
export default function NotFound() {
  return <h1>404 - Page not found</h1>;
}

Q25. What are Server Actions? How do you use them?

Server Actions are async functions marked with "use server" that run on the server when called from a Client Component (or a form). They let you mutate data, update the database, and revalidate cache - all without writing a separate API route. They're the App Router's answer to form submissions and mutations.

// app/actions.ts - server-only file
"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("/blog"); // bust the /blog page cache
}
// app/new-post/page.tsx - Client or Server Component can use the action
import { createPost } from "@/app/actions";

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

Q26. What is `revalidatePath` vs `revalidateTag`?

revalidatePath("/blog") purges the cache for a specific URL path. revalidateTag("posts") purges all fetch calls tagged with "posts" anywhere in the app. Use revalidatePath when you know exactly which page changed; use revalidateTag when multiple pages share the same underlying data.

// Tag fetch calls at the data layer
const posts = await fetch("https://api/posts", {
  next: { tags: ["posts"] },
}).then((r) => r.json());

// In a Server Action: bust all "posts"-tagged fetches site-wide
import { revalidateTag } from "next/cache";
export async function deletePost(id: string) {
  await db.post.delete({ where: { id } });
  revalidateTag("posts"); // blog list, homepage feed, related posts - all revalidated
}

Q27. What is the `redirect` function in the App Router?

redirect() from next/navigation performs a server-side redirect - it throws internally (using React's error boundary mechanism) and sends a 307 redirect. Use it in Server Components and Server Actions. For client-side navigation, use useRouter().push().

// app/dashboard/page.tsx - server-side redirect
import { redirect } from "next/navigation";
import { getSession } from "@/lib/auth";

export default async function Dashboard() {
  const session = await getSession();
  if (!session) redirect("/login"); // sends 307, never returns
  return <DashboardContent user={session.user} />;
}

Q28. What is `generateStaticParams`?

generateStaticParams replaces getStaticPaths in the App Router. It returns the list of param values to pre-render at build time for dynamic routes. Next.js pre-builds one static page per returned object and falls back to on-demand rendering for any slug not in the list.

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetchAllPosts();
  return posts.map((p) => ({ slug: p.slug }));
  // → pre-renders /blog/post-1, /blog/post-2, etc.
}

export default async function BlogPost({
  params,
}: {
  params: { slug: string };
}) {
  const post = await fetchPost(params.slug);
  return <article>{post.content}</article>;
}

Q29. How do you read cookies and headers inside a Server Component?

Use cookies() and headers() from next/headers. These are async functions in Next.js 15+ (they were synchronous in earlier versions - a common source of bugs). Calling them makes the component dynamic (not statically cached).

import { cookies, headers } from "next/headers";

export default async function ProfilePage() {
  const cookieStore = await cookies();
  const token = cookieStore.get("authToken")?.value;

  const headersList = await headers();
  const userAgent = headersList.get("user-agent");

  if (!token) redirect("/login");
  const user = await getUserFromToken(token);
  return <Profile user={user} />;
}

Q30. What is `generateMetadata`?

generateMetadata is an async function exported from a page.tsx or layout.tsx that returns SEO metadata (title, description, OG tags). It replaces the component from the Pages Router. It can receive params, so dynamic routes can generate page-specific titles.

// app/blog/[slug]/page.tsx
export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}) {
  const post = await fetchPost(params.slug);
  return {
    title: `${post.title} | My Blog`,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      images: [{ url: post.coverImage }],
    },
  };
}

Section 3 - Advanced & Production (Q31–Q40)

These questions separate candidates who have deployed Next.js to production from those who've only built tutorials. They probe middleware, caching internals, authentication patterns, and deployment decisions.

The most common gap I've seen in mid-level Next.js developers is treating the App Router like the Pages Router with different file names. The mental shift that unlocks App Router mastery is: "Server Components are the default. Push state and interactivity to the edges of the component tree." Once that clicks, caching, Server Actions, and streaming all fall into place.

Server rack visualization representing Next.js edge runtime and server-side rendering infrastructure
Server rack visualization representing Next.js edge runtime and server-side rendering infrastructure

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

Middleware is a function in middleware.ts at the project root that runs before every matched request - on the Edge Runtime (not Node.js). It intercepts requests before they hit a page or API route, making it ideal for auth checks, redirects, A/B testing, and header injection. Edge Runtime means it runs close to the user with sub-millisecond cold starts.

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

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

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

  return NextResponse.next();
}

// Only run middleware on these paths
export const config = {
  matcher: ["/dashboard/:path*", "/api/protected/:path*"],
};

Interview tip: Middleware runs on the Edge Runtime - it can't use Node.js APIs like fs or crypto. Keep it thin: auth checks, redirects, and header manipulation only.


Q32. How does the App Router caching model work?

The App Router has four caching layers that work together:

CacheWhat it storesDurationInvalidated by
Request MemoizationDuplicate fetch calls in one renderSingle requestAutomatic
Data Cachefetch resultsIndefinitely (or revalidate)revalidatePath, revalidateTag
Full Route CacheStatic HTML + RSC payloadUntil redeployment / revalidationDeploys, revalidation
Router CacheRSC payload in browserSession (30s–5min)Navigation, router.refresh()

Understanding which cache a problem lives in is the skill interviewers are probing.


Q33. What does `cache: 'force-cache'` vs `cache: 'no-store'` do?

cache: 'force-cache' (default) caches the fetch response indefinitely in the Data Cache - behavior identical to getStaticProps. cache: 'no-store' bypasses the Data Cache entirely on every request - behavior identical to getServerSideProps. next: { revalidate: N } is ISR: cached but regenerated after N seconds.

// Static (default) - cached forever, fastest
const data = await fetch("/api/config");

// ISR - cached for 10 minutes, then regenerated on next request
const posts = await fetch("/api/posts", { next: { revalidate: 600 } });

// SSR - never cached, always hits the origin
const cart = await fetch("/api/cart", { cache: "no-store" });

Q34. What is Partial Prerendering (PPR)?

PPR (experimental, Next.js 14+) splits a single page into a static shell and dynamic holes. The static shell is pre-rendered at build time and served instantly from the CDN. Dynamic sections (wrapped in Suspense) are streamed in from the server. It's the convergence of SSG and SSR on one page - no trade-off required.

// app/product/[id]/page.tsx
// With PPR enabled, the shell (ProductInfo) renders statically
// while Reviews stream dynamically - same page, same URL
import { Suspense } from "react";

export default async function ProductPage({ params }) {
  return (
    <>
      <ProductInfo id={params.id} /> {/* static shell - CDN-served */}
      <Suspense fallback={<ReviewSkeleton />}>
        <Reviews id={params.id} /> {/* dynamic hole - streamed from server */}
      </Suspense>
    </>
  );
}

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

The recommended pattern: validate the session in Middleware for route protection, read the session in Server Components for personalization, and use Server Actions for login/logout mutations. Libraries like Auth.js (formerly NextAuth) and Clerk integrate with this pattern out of the box.

// middleware.ts - protect routes before they render
import { auth } from "@/auth"; // Auth.js helper

export default auth((req) => {
  if (!req.auth && req.nextUrl.pathname.startsWith("/dashboard")) {
    return Response.redirect(new URL("/login", req.url));
  }
});

// app/dashboard/page.tsx - read session in Server Component
import { auth } from "@/auth";

export default async function Dashboard() {
  const session = await auth(); // reads from cookie/JWT on the server
  return <h1>Welcome, {session?.user?.name}</h1>;
}

// app/actions.ts - Server Action for logout
("use server");
import { signOut } from "@/auth";
export async function logout() {
  await signOut({ redirectTo: "/" });
}

Q36. What is the `use cache` directive? (Next.js 15)

"use cache" is a Next.js 15 experimental directive that marks a function or component's output for caching in the Data Cache. It's more granular than the fetch cache option - you can cache any async operation, not just fetch calls. Combine with cacheTag() and cacheLife() for fine-grained control.

// Cache an expensive database query (not a fetch call)
import {
  unstable_cacheTag as cacheTag,
  unstable_cacheLife as cacheLife,
} from "next/cache";

async function getTopProducts() {
  "use cache";
  cacheLife("hours"); // cache for up to 1 hour
  cacheTag("products"); // invalidate with revalidateTag("products")

  return await db.product.findMany({ orderBy: { sales: "desc" }, take: 10 });
}

Q37. What is the difference between API Routes and Route Handlers?

API Routes (/pages/api/.ts) are the Pages Router way to create backend endpoints. Route Handlers (/app/api//route.ts) are the App Router equivalent. Route Handlers use the standard Request/Response Web APIs (no Express-style req, res), support GET, POST, PUT, DELETE, etc. as named exports, and run on the Edge Runtime by default.

// app/api/posts/route.ts - Route Handler
import { NextResponse } from "next/server";

// Named exports per HTTP method
export async function GET() {
  const posts = await db.post.findMany();
  return NextResponse.json(posts);
}

export async function POST(request: Request) {
  const body = await request.json();
  const post = await db.post.create({ data: body });
  return NextResponse.json(post, { status: 201 });
}

Interview tip: In the App Router, prefer Server Actions over Route Handlers for mutations (form submissions, data writes) - they're simpler, type-safe, and don't require a separate HTTP endpoint.


Q38. How does Next.js optimize fonts and third-party scripts?

next/font self-hosts Google Fonts at build time, eliminating the external network request and layout shift. next/script provides a strategy prop - "lazyOnload" defers scripts until the browser is idle, "afterInteractive" loads after hydration, "beforeInteractive" loads before hydration (for critical scripts like consent managers).

import Script from "next/script";

// Third-party analytics - load after page is interactive
<Script
  src="https://www.googletagmanager.com/gtag/js?id=GA_ID"
  strategy="afterInteractive"
/>

// Partytown worker pattern - run heavy scripts off the main thread
<Script
  src="https://example.com/heavy-analytics.js"
  strategy="worker"
/>

Q39. How do you deploy Next.js? What is the difference between Vercel and self-hosted?

Vercel is the reference deployment platform - zero config, automatic ISR/Edge caching, image optimization CDN, preview deployments per PR. Self-hosted (Node.js server via next start, Docker, or standalone output) gives you full infrastructure control but requires you to manage ISR revalidation, image optimization server, and edge caching yourself.

# Self-hosted: Docker with standalone output (Next.js 13+)
FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build

FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

EXPOSE 3000
CMD ["node", "server.js"]
// next.config.js - enable standalone output for Docker
module.exports = {
  output: "standalone", // produces a self-contained server bundle
};

Q40. What are the most impactful Next.js performance optimizations in production?

According to Vercel's own benchmarks and production case studies, the top performance wins in Next.js applications are: Server Components (reduces client JS), next/image with priority on LCP images, next/font for zero CLS, route-level code splitting (automatic), Suspense streaming for slow data, and the revalidate/revalidateTag caching strategy over cache: 'no-store' wherever possible.

// 1. Push "use client" to leaf components only (reduces JS bundle)
// ❌ Entire page is a Client Component
"use client";
export default function ProductPage() { ... }

// ✅ Only the interactive button is a Client Component
export default async function ProductPage() {   // Server Component
  const product = await fetchProduct();
  return (
    <>
      <ProductDetails product={product} />     {/* Server Component */}
      <AddToCartButton productId={product.id} /> {/* Client Component */}
    </>
  );
}

// 2. Tag all fetch calls for granular cache invalidation
const data = await fetch("/api/products", { next: { tags: ["products"] } });

// 3. Use generateStaticParams for dynamic routes with known slugs
export async function generateStaticParams() {
  return (await fetchAllSlugs()).map(s => ({ slug: s }));
}

Frequently Asked Questions

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

Next.js 14 and 15 are the interview targets. Next.js 14 introduced stable Server Actions and Partial Prerendering (experimental). Next.js 15 made cookies(), headers(), and params async, added "use cache", and improved React 19 compatibility. Understand the App Router - it's been the default since Next.js 13.4.

Next.js 14 vs 15 differences → detailed comparison of what changed between Next.js 14 and 15

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

Yes, but contextually. Companies with existing codebases ask about getStaticProps, getServerSideProps, and _app.js. Greenfield roles focus entirely on the App Router. The safest approach: know Pages Router concepts well enough to compare them to App Router equivalents - interviewers often ask "how would you do X in the App Router that used to require getServerSideProps?"

When should you use a Server Action vs an API Route Handler?

Use a Server Action for mutations triggered by forms or button clicks within your Next.js app - they're type-safe, co-located with the component, and automatically handle revalidation. Use a Route Handler when you need a public REST API consumed by external clients (mobile apps, third-party integrations, webhooks), or when you need fine-grained control over HTTP headers and status codes.

How do you handle loading states in the App Router?

Three options, in order of preference: (1) loading.tsx - automatic Suspense boundary for the entire route segment; (2) wrappers - granular boundaries for individual async components within a page; (3) Client Components with useTransition - for interactions that trigger data refetches. Avoid useEffect-based loading states in the App Router - they shift data fetching to the client unnecessarily.

What is the difference between `useRouter` from `next/navigation` vs `next/router`?

next/navigation is the App Router import (useRouter, usePathname, useSearchParams, useParams). next/router is the Pages Router import. Never mix them. In the App Router, useSearchParams() must be wrapped in a Suspense boundary because it opts the component into client-side rendering.

Next.js App Router migration guide → step-by-step guide to migrating from Pages Router to App Router


Conclusion

Next.js interview questions in 2026 span three layers: the foundational routing and rendering model, the App Router's Server Component architecture, and production concerns like caching, auth, middleware, and deployment. The questions that filter candidates aren't definitions - they're architectural: "where would you put this logic, and why?"

The gap most candidates have isn't knowledge of Next.js features - it's the mental model shift from Pages Router thinking to App Router thinking. Server Components are the default. Data fetching belongs in the component, not in lifecycle methods. Interactivity lives at the leaf level, not the page level. Work through the code examples in this guide until that model feels natural, and the interview questions will follow.

Key Takeaways

  • App Router fundamentals (Server Components, layouts, loading.tsx, error.tsx) are table stakes - know them cold

  • Data fetching: fetch with cache: 'no-store' = SSR; next.revalidate = ISR; default = SSG

  • Server Actions replace most API routes for mutations - understand them and revalidateTag

  • Middleware + Server Components + Server Actions is the auth pattern interviewers expect in 2026

React interview questions 2026 → complete guide to React hooks, Server Components, and modern React 18/19

Node.js interview questions 2026 → backend fundamentals and Node.js runtime questions for full-stack interviews

Author: Abhijeet Kushwaha | Last updated: April 2026

More from React & Frontend

⚛️

30 Golden Frontend Topics Every Senior Developer Must Master in 2026

18 min read

⚛️

The Modern React Stack in 2026: Zustand, TanStack Query, Tailwind, and shadcn/ui Explained

18 min read

⚛️

React Server Components Security in 2026: CVEs, the React Foundation, and What It All Means for You

10 min read

Browse All Articles