Next.js Senior Interview Questions
Real-world interview questions for Senior Next.js Developers, covering App Router, Server Actions, Caching, and Performance.
⚡ Core & App Router
1. Explain the difference between Server Components (RSC) and Client Components.
Server Components (Default) are rendered only on the server. They send zero JavaScript to the browser, just HTML. They can access the database/fs directly but cannot use hooks (useState, useEffect) or event listeners (onClick).
Client Components ('use client') are rendered on the server (initial HTML) AND hydrated on the client. They are standard React components that can have interactivity.
🧠 Memory tip: Server = No JS/Hooks (Data); Client = Interactivity (Buttons/State).
2. How does the Nested Layouts system work in the App Router?
In the app directory, a layout.tsx wraps all routes inside its folder.
If you have app/dashboard/layout.tsx and app/dashboard/settings/page.tsx, the Settings page is wrapped by the Dashboard layout, which is wrapped by the Root layout.
This allows state preservation (like keeping a Sidebar scroll position) while navigating between child pages.
🧠 Memory tip: Layouts nest like Russian dolls and preserve state.
3. What are Route Groups and why would you use them?
Route groups are folders with parentheses, like (marketing).
They allow you to organize your code logically without affecting the URL path.
Example: app/(marketing)/about/page.tsx serves at /about, NOT /marketing/about.
They are also crucial for opting out of a shared layout (e.g., creating a different Root Layout for the Admin section vs the Marketing section).
🧠 Memory tip: (Groups) organize files but don’t change URLs.
4. What is the purpose of `loading.tsx` and `error.tsx` files?
- loading.tsx: Automatically wraps the page in a React Suspense boundary. It shows this UI immediately while the page’s async data is fetching.
- error.tsx: Automatically wraps the page in a React Error Boundary. If an error occurs during rendering, this UI is shown instead of crashing the whole app.
🧠 Memory tip: File-system based Suspense and Error Boundaries.
5. How do you handle Dynamic Routes in App Router?
You create a folder with brackets: app/blog/[slug]/page.tsx.
The component receives params as a prop.
export default function Page({ params }: { params: { slug: string } }) { ... }
To generate them statically at build time, you export the generateStaticParams function from that same file.
🧠 Memory tip: [Brackets] = Dynamic Params.
6. What is the Edge Runtime vs Node.js Runtime?
- Node.js: The full Node environment. Supports all npm packages and native modules. Heavier start-up (Cold start).
- Edge: A lightweight subset of APIs (V8 isolate). Starts instantly (0ms cold start). Great for middleware and simple APIs, but cannot use Node-specific APIs (like
fsor database drivers that depend on TCP/native events).
🧠 Memory tip: Edge = Fast but Limited; Node = Heavy but Compatible.
7. Explain "Parallel Routes" and when to use them.
Parallel routes use “Slots” (measured folders like @team).
They allow you to render multiple pages in the same layout simultaneously and conditionally.
Example: A dashboard that loads @analytics and @team side-by-side. If @analytics is slow, it shows its own loading state without blocking @team.
🧠 Memory tip: Slots (@) allow multiple independent pages in one view.
8. What is "Intercepting Routes"?
It allows you to load a route from another part of the app within the current layout (like a modal).
Example: Clicking a photo in a feed opens /photo/123.
- If clicked from the feed, it acts as a Modal (intercepted).
- If you refresh the page (direct visit), it renders the full separate Photo Page.
Syntax:
(..)photo.
🧠 Memory tip: Load a URL as a Modal without leaving the page.
⚙️ Data Fetching & Caching
1. How does `fetch` behave differently in Next.js App Router?
Next.js patches the native fetch API to add caching defaults.
fetch('...')defaults toforce-cache(Static Site Generation behavior). It gets data once at build time.fetch('...', { cache: 'no-store' })makes it dynamic (Server Side Rendering behavior). It runs on every request.fetch('...', { next: { revalidate: 60 } })is Incremental Static Regeneration (ISR).
🧠 Memory tip: Fetch is extended to control Build vs Runtime caching.
2. What are Server Actions?
Server Actions are asynchronous functions that run on the server, callable directly from Client Components (like forms).
Instead of creating a separate API route (/api/submit), you just write a function async function register() { 'use server'; ... } and pass it to the form action.
They handle the “POST” request cycle automatically.
🧠 Memory tip: Type-safe RPC calls; no need for api/ folder.
3. Explain Request Memoization vs Data Cache.
- Request Memoization: Caches the same fetch request within a single render pass. If Layout and Page both fetch
getUser(), Next.js only calls the API once. (Lasts: Milliseconds). - Data Cache: Persistent HTTP cache across all users and requests. This is the “build time” or “revalidated” data. (Lasts: Until revalidated).
🧠 Memory tip: Memoization = Per Request (Deduping); Data Cache = Persistent (Storage).
4. How does Revalidation work (ISR)?
It updates static content without rebuilding the whole site.
- Time-based:
revalidate: 60. If a user visits after 60s, they see the old page (stale), but Next.js triggers a background regeneration. The next person sees the new page (stale-while-revalidate). - **On-demand
:revalidatePath(‘/blog’)orrevalidateTag(‘posts’)`. You manually trigger this (e.g., via a Webhook from your CMS) to update content instantly.
🧠 Memory tip: Update static HTML in the background.
5. Why would you use `generateStaticParams`?
Used in dynamic routes ([slug]) to statically generate pages at build time.
If you return [{ slug: 'a' }, { slug: 'b' }], Next.js builds those HTML files.
If dynamicParams is true (default), other slugs ('c') will be generated on-demand (SSR) the first time they are accessed, then cached.
🧠 Memory tip: The modern getStaticPaths.
6. How do you fetch data in a Client Component?
You usually shouldn’t. It’s better to fetch in a Server Component and pass data as props.
If you must (e.g., polling key), use a library like SWR or TanStack Query.
Do not use useEffect + fetch directly without a library, as it lacks deduplication, caching, and race-condition handling.
🧠 Memory tip: Fetch on Server; if Client, use SWR/React Query.
🚄 Optimization & Performance
1. How does the `next/image` component optimize request performance?
It automatically:
- Resizes images: Serves smaller files to mobile devices.
- Formats: Converts to WebP/AVIF (modern formats).
- Lazy Loads: Does not load the image until it enters the viewport.
- Prevents CLS: Allocates space (width/height) to stop layout shift.
🧠 Memory tip: Auto-resize, Auto-format, Auto-lazy, No Shift.
2. What is `next/font`?
It optimizes fonts (Google Fonts or local) by downloading them at build time and self-hosting them with the static assets. This removes the layout shift (CLS) caused by fonts swapping or loading late, and prevents any external network requests to Google during page load.
🧠 Memory tip: Zero layout shift; self-hosted automatically.
3. How do you implement SEO metadata in App Router?
You export a metadata object (or generateMetadata function) from a page.tsx or layout.tsx.
export const metadata = {
title: 'My Page',
description: '...'
}
Metadata inside nested layouts merges automatically (e.g., Root layout sets the og:image, Page sets the title).
🧠 Memory tip: Export metadata object; it merges down the tree.
4. What is `lazy` loading specifically for Components?
Using next/dynamic.
const HeavyComponent = dynamic(() => import('./Heavy')).
This creates a separate JavaScript chunk for that component. It is not downloaded until the component is actually rendered.
Crucial for heavy UI elements like Maps, 3D Models, or Rich Text Editors.
🧠 Memory tip: next/dynamic splits the bundle.
5. What is Partial Prerendering (PPR)?
Experimental Feature. It allows a page to be partially static and partially dynamic. The outer shell (Layout, Header) is pre-rendered/static (served instantly from Edge). The dynamic parts (User Profile) are streamed in parallel. It combines the best of SSG (Speed) and SSR (Dynamic Data).
🧠 Memory tip: Static Shell + Dynamic Holes.
🧩 Architecture & Best Practices
1. What is Middleware used for in Next.js?
It runs before a request completes. Common use cases:
- Authentication: Checking cookies and redirecting to
/login. - Localization: Rewriting URLs based on
Accept-Languageheader (e.g.,/->/fr). - A/B Testing: Rewriting users to different page buckets. It runs on the Edge, so it must be fast.
🧠 Memory tip: The Gatekeeper for every request.
2. How do you handle Environment Variables safely?
ANALYTICS_ID: Available on the Server only.NEXT_PUBLIC_ANALYTICS_ID: Available on the Client (browser). Next.js inlinesNEXT_PUBLIC_variables into the JS bundle at build time. Keeping secrets (API Keys) without the prefix ensures they never leak to the browser.
🧠 Memory tip: NEXT_PUBLIC_ for Browser; No prefix for Server Secrets.
3. Why use "Composition Pattern" (passing children) in Server Components?
If a component needs context (Theme) or interactivity, it must be a Client Component.
If you import a Server Component into a Client Component file, it becomes a Client Component (de-optimized).
Fix: Pass the Server Component as a children prop to the Client Component wrapper.
<ClientWrapper><ServerContent /></ClientWrapper>
This keeps the ServerContent rendering on the server.
🧠 Memory tip: Pass Server Components as children to keep them Server-side.
4. Explain `streaming` with React Suspense.
Streaming allows the server to send the HTML in chunks.
Instead of waiting for all data API calls to finish before generating the page, Next.js sends the header/layout immediately.
Then, as each Suspense boundary resolves (data arrives), it sends that chunk of HTML to the browser alongside a small script to inject it.
Improves TTFB (Time to First Byte).
🧠 Memory tip: Send HTML piece by piece as it’s ready.
5. How would you architect a Next.js app for high scale?
- Caching: Aggressively use Data Cache and ISR for public pages.
- CDN: Deploy to Vercel/Cloudflare/AWS to serve static assets from the edge.
- DB: Use a serverless-friendly DB (Postgres/Redis) with connection pooling.
- Image Optimization: Offload image processing to a dedicated service if volume is huge.
- Sharding: Use Multi-Zones (rewrites) to split a massive app into different Next.js deployments.
🧠 Memory tip: Cache aggressively, Serve from Edge, optimize DB connections.