codejump

Interview questionsNext.js

Next.js interview questions and answers

30 Next.js questions picked from Codejump's quizzes, from the basics a junior is expected to know to the details that trip up senior candidates. Each one comes with its answer and an explanation — try to answer before you open it.

Junior level Next.js questions

  1. 1.Why use next/image instead of a plain <img> tag?

    javascript
    import Image from 'next/image';
    <Image src="/hero.jpg" alt="Hero" width={800} height={450} priority />
    • A.next/image automatically optimises images — modern format conversion (WebP/AVIF), lazy loading by default, responsive srcset generation, and reserved space from width/height to prevent layout shift
    • B.<img> is deprecated in Next.js
    • C.next/image only works with files in the public/ folder
    • D.In production, <img> and next/image behave identically
    Show answer

    Answer: A. next/image automatically optimises images — modern format conversion (WebP/AVIF), lazy loading by default, responsive srcset generation, and reserved space from width/height to prevent layout shift

    next/image serves images through a built-in optimisation endpoint: it converts to efficient formats, generates multiple sizes so the browser downloads only what the layout needs, lazy-loads off-screen images, and uses the width/height (or fill) to reserve layout space and avoid Cumulative Layout Shift. A plain <img> does none of this.

    From the quiz Routing & Pages

  2. 2.How do these two calls differ?

    javascript
    await fetch('https://api.example.com/data');
    await fetch('https://api.example.com/data', { cache: 'no-store' });
    • A.They are identical — fetch always hits the network
    • B.The first fails in Server Components
    • C.no-store stores the data in memory instead of on disk
    • D.The first uses whatever the default cache behaviour is (cached in Next.js 14, not cached in Next.js 15); cache: 'no-store' explicitly never caches, so it re-fetches on every request and marks the route dynamic
    Show answer

    Answer: D. The first uses whatever the default cache behaviour is (cached in Next.js 14, not cached in Next.js 15); cache: 'no-store' explicitly never caches, so it re-fetches on every request and marks the route dynamic

    Next.js extends fetch with a Data Cache. In Next.js 14 an un-annotated fetch was cached by default; Next.js 15 reversed that, so it is now uncached unless you opt in with cache: 'force-cache' or next: { revalidate }. cache: 'no-store' is the explicit always fresh form and opts the route into dynamic rendering.

    From the quiz SSR & SSG Basics

  3. 3.How do you set the page <title> and <meta name="description"> in the App Router?

    javascript
    export const metadata = { title: 'Home', description: '...' };
    // or
    export async function generateMetadata({ params }) { /* ... */ }
    • A.Add a <title> tag directly inside your JSX
    • B.Use <Head> from next/head inside the page component
    • C.Export a metadata object (for static values) or a generateMetadata function (for dynamic values) from page.tsx or layout.tsx
    • D.Configure all metadata globally in next.config.ts
    Show answer

    Answer: C. Export a metadata object (for static values) or a generateMetadata function (for dynamic values) from page.tsx or layout.tsx

    The App Router replaces next/head with the Metadata API. Export a metadata object when the values are known statically, or an async generateMetadata function when they depend on route params or fetched data. Next.js merges metadata from the layout and page (child values win) and injects the resulting tags into <head>.

    From the quiz Routing & Pages

  4. 4.How does loading.tsx work?

    javascript
    app/dashboard/
    ├── loading.tsx
    └── page.tsx     (async, awaits data)
    • A.It shows while the entire HTML document downloads
    • B.Next.js automatically wraps the segment's page.tsx in a <Suspense> boundary whose fallback is loading.tsx, shown while the async Server Component resolves — for both the initial load and client-side navigation
    • C.You must add <Suspense> in page.tsx yourself for it to work
    • D.It only shows a spinner during client-side navigation
    Show answer

    Answer: B. Next.js automatically wraps the segment's page.tsx in a <Suspense> boundary whose fallback is loading.tsx, shown while the async Server Component resolves — for both the initial load and client-side navigation

    loading.tsx is wired up as an automatic Suspense boundary around the segment. While the server renders page.tsx (or a nested route without its own closer loading.tsx), the browser shows the loading UI, then swaps in the real content as it streams. No manual <Suspense> is required for this segment-level behaviour.

    From the quiz SSR & SSG Basics

  5. 5.Which environment variable prefix makes a value available in browser code?

    javascript
    DATABASE_URL="postgresql://..."          # ?
    NEXT_PUBLIC_API_URL="https://api.app"    # ?
    • A.All variables in .env.local are automatically available in the browser
    • B.Only variables prefixed with NEXT_PUBLIC_ are inlined into the client bundle; every other variable is server-only and is undefined in browser code
    • C.The PUBLIC_ prefix exposes a variable
    • D.Every variable is available everywhere by default
    Show answer

    Answer: B. Only variables prefixed with NEXT_PUBLIC_ are inlined into the client bundle; every other variable is server-only and is undefined in browser code

    Next.js only exposes variables whose name begins with NEXT_PUBLIC_ to client-side code, replacing them with their literal value at build time. Variables without that prefix stay on the server — a Server Component or Route Handler can read process.env.DATABASE_URL, but the same access in a Client Component returns undefined. This keeps secrets out of the browser bundle by default.

    From the quiz Routing & Pages

  6. 6.What is a Server Action?

    javascript
    async function createPost(formData: FormData) {
      'use server';
      await prisma.post.create({ data: { title: String(formData.get('title')) } });
      revalidatePath('/blog');
    }
    • A.A Route Handler that serves GET requests
    • B.A Server Component that performs database operations
    • C.An async function marked "use server" that runs on the server and can be invoked directly from a form (<form action={fn}>) or a Client Component — letting you do mutations without hand-writing an API endpoint
    • D.The same thing as getServerSideProps
    Show answer

    Answer: C. An async function marked "use server" that runs on the server and can be invoked directly from a form (<form action={fn}>) or a Client Component — letting you do mutations without hand-writing an API endpoint

    A Server Action is a function Next.js compiles into a callable server endpoint. You pass it to <form action={…}> or call it from client code; it runs on the server (always over POST), can read FormData, mutate data, and call revalidatePath/redirect. It replaces most bespoke POST API routes for form/mutation flows, and it is progressively enhanced (works before hydration).

    From the quiz SSR & SSG Basics

  7. 7.Where do you put static assets (favicons, robots.txt, images) that should be served from the site root?

    javascript
    public/favicon.ico   → served at /favicon.ico
    public/logo.png      → served at /logo.png
    • A.In src/static/
    • B.In app/assets/
    • C.In app/static/
    • D.In public/ — anything there is served at the root path (e.g. public/robots.txt is available at /robots.txt)
    Show answer

    Answer: D. In public/ — anything there is served at the root path (e.g. public/robots.txt is available at /robots.txt)

    The public/ directory at the project root is the static asset folder. Files map directly to root-relative URLs, so public/logo.png is reachable at /logo.png and referenced in code as src="/logo.png". No other folder name has this behaviour.

    From the quiz Routing & Pages

  8. 8.What is the difference between "use server" and "use client"?

    • A."use client" is a file-level directive that makes a module's components Client Components (able to use hooks and browser APIs); "use server" marks async functions as Server Actions (callable from the client, executed on the server) — it is not a component directive
    • B.They are opposites — "use server" makes a component render on the server
    • C."use server" is the default for every file
    • D.Both can appear in the same file
    Show answer

    Answer: A. "use client" is a file-level directive that makes a module's components Client Components (able to use hooks and browser APIs); "use server" marks async functions as Server Actions (callable from the client, executed on the server) — it is not a component directive

    "use client" sits at the top of a module and shifts it (and its imports) into the client bundle. "use server" sits at the top of a function (or the top of a dedicated actions file, making all its exports actions) and designates Server Actions. Components are already server-rendered by default, so "use server" never moves a component to the server.

    From the quiz SSR & SSG Basics

  9. 9.What is next.config.ts used for?

    javascript
    import type { NextConfig } from 'next';
    const config: NextConfig = { images: { remotePatterns: [...] }, async redirects() { ... } };
    export default config;
    • A.Configuring build and server behaviour: allowed image domains, redirects, rewrites, custom headers, experimental flags, and webpack/Turbopack customisation
    • B.Defining the React components for the root layout
    • C.Storing environment variables (it replaces .env)
    • D.Declaring TypeScript types for the project
    Show answer

    Answer: A. Configuring build and server behaviour: allowed image domains, redirects, rewrites, custom headers, experimental flags, and webpack/Turbopack customisation

    next.config.ts is the framework configuration file. It runs in Node.js at build/startup time and controls things like image optimisation settings, HTTP redirects() and rewrites(), response headers(), experimental feature toggles, and low-level bundler options.

    From the quiz Routing & Pages

  10. 10.What does generateStaticParams do?

    javascript
    export async function generateStaticParams() {
      const posts = await getPosts();
      return posts.map((p) => ({ slug: p.slug }));
    }
    • A.It generates the page title from the URL params
    • B.It validates that params exist before rendering
    • C.It replaces getStaticPaths and must be used on every dynamic route
    • D.It tells Next.js which values of a dynamic segment to prerender at build time — the returned array of param objects becomes a set of static pages; values not listed render on demand by default (or 404 if dynamicParams = false)
    Show answer

    Answer: D. It tells Next.js which values of a dynamic segment to prerender at build time — the returned array of param objects becomes a set of static pages; values not listed render on demand by default (or 404 if dynamicParams = false)

    generateStaticParams enumerates the dynamic segment values to build ahead of time. Return three { slug } objects and Next.js prerenders three pages. It is optional — without it, the route is server-rendered per request. Pair it with revalidate for ISR and dynamicParams to control unlisted values.

    From the quiz SSR & SSG Basics

Mid level Next.js questions

  1. 11.When should you use generateMetadata instead of the static metadata export?

    javascript
    export const metadata = { title: 'Home' };
    // vs
    export async function generateMetadata({ params }) {
      const post = await getPost((await params).slug);
      return { title: post.title };
    }
    • A.Always use generateMetadata — the static metadata export is deprecated
    • B.Use generateMetadata when the metadata depends on dynamic data (route params, a database record, the current user); use the static metadata export for fixed titles and descriptions
    • C.generateMetadata is only for Route Handlers
    • D.You can export both metadata and generateMetadata from the same file
    Show answer

    Answer: B. Use generateMetadata when the metadata depends on dynamic data (route params, a database record, the current user); use the static metadata export for fixed titles and descriptions

    Reach for generateMetadata — an async function that receives params and searchParams — only when the tags depend on something you have to look up. For a page whose title never changes, the plain metadata object is simpler and just as valid.

    From the quiz API Routes & Middleware

  2. 12.What does React.cache() do?

    javascript
    import { cache } from 'react';
    const getUser = cache(async (id: string) => prisma.user.findUnique({ where: { id } }));
    • A.It stores data in Redis for future requests
    • B.It is equivalent to unstable_cache and persists across requests
    • C.It memoises the function within a single request — calls with the same arguments during one render share a result — and the cache is discarded when the request ends
    • D.It only works with fetch(), not custom functions
    Show answer

    Answer: C. It memoises the function within a single request — calls with the same arguments during one render share a result — and the cache is discarded when the request ends

    React.cache() gives request-scoped memoization for arbitrary async functions. If a layout and several components all call getUser('123') during one render, the query runs once. Nothing is kept between requests — for that you use unstable_cache / the fetch cache. A common use is sharing a lookup between generateMetadata and the page.

    From the quiz ISR & Revalidation

  3. 13.How do you create an API endpoint in the App Router?

    javascript
    // app/api/users/route.ts
    export async function GET(request: Request) { /* ... */ }
    export async function POST(request: Request) { /* ... */ }
    • A.Export getServerSideProps from app/api/users/page.tsx
    • B.Create pages/api/users.ts — only the Pages Router supports API routes
    • C.Define the endpoint in next.config.ts
    • D.Create app/api/users/route.ts and export named functions for each HTTP method (GET, POST, PUT, DELETE, …)
    Show answer

    Answer: D. Create app/api/users/route.ts and export named functions for each HTTP method (GET, POST, PUT, DELETE, …)

    In the App Router, a route.ts (or route.js) file defines an endpoint for its URL segment. You export an async function per HTTP method; each receives a standard Web Request and returns a Web Response (often via NextResponse.json()). Route Handlers replace pages/api/* for App Router projects.

    From the quiz API Routes & Middleware

  4. 14.How do you implement Incremental Static Regeneration in the App Router?

    • A.Export getStaticProps returning { revalidate: 60 }
    • B.Set next: { revalidate: 60 } on a fetch call, or export const revalidate = 60 at the segment level — the route is prerendered at build and regenerated in the background at most every N seconds
    • C.ISR is not supported in the App Router
    • D.Use unstable_cache with revalidate: 60 — the only option
    Show answer

    Answer: B. Set next: { revalidate: 60 } on a fetch call, or export const revalidate = 60 at the segment level — the route is prerendered at build and regenerated in the background at most every N seconds

    ISR is either per-fetch (next: { revalidate }) or per-segment (export const revalidate). After the window elapses, the next request serves the stale prerender and triggers a background regeneration. Tag-based on-demand invalidation (revalidateTag) complements the timer.

    From the quiz ISR & Revalidation

  5. 15.What is the difference between redirect() from next/navigation and useRouter().push()?

    • A.They are identical — use either
    • B.redirect() only works with external URLs
    • C.redirect() is a server-side function (usable in Server Components, Route Handlers, and Server Actions) that triggers a redirect by throwing an internal signal; useRouter().push() is a client hook method for programmatic navigation from a Client Component
    • D.useRouter() is available in Server Components
    Show answer

    Answer: C. redirect() is a server-side function (usable in Server Components, Route Handlers, and Server Actions) that triggers a redirect by throwing an internal signal; useRouter().push() is a client hook method for programmatic navigation from a Client Component

    redirect() runs during server work — call it in a Server Component's render, a Route Handler, or a Server Action, and Next.js turns it into an HTTP redirect (or a client navigation for actions). useRouter() is a hook, so it only works in a "use client" component, and you call router.push() / router.replace() in an event handler.

    From the quiz API Routes & Middleware

  6. 16.What does useOptimistic enable?

    javascript
    'use client';
    const [optimisticTodos, addOptimistic] = useOptimistic(todos, (state, t: Todo) => [...state, t]);
    • A.It makes Server Actions run synchronously
    • B.It caches Server Action results
    • C.It is a third-party library
    • D.It lets the UI immediately show the expected result of a pending mutation (layered over the real state); when the action completes and the component re-renders with fresh data, the optimistic layer is dropped — and if the mutation fails and no new data arrives, it reverts
    Show answer

    Answer: D. It lets the UI immediately show the expected result of a pending mutation (layered over the real state); when the action completes and the component re-renders with fresh data, the optimistic layer is dropped — and if the mutation fails and no new data arrives, it reverts

    useOptimistic(base, reducer) shows reducer(base, payload) during a pending action/transition, then reconciles back to base once real data is in. It is purely presentational — the source of truth stays the todos prop, which must be revalidated on the server so the new item persists after the optimistic layer clears.

    From the quiz ISR & Revalidation

  7. 17.How do you read URL query parameters in a Server Component for /products?category=shoes?

    • A.A Server Component receives searchParams as a prop. In Next.js 15 it is a Promise, so you await it: const { category } = await searchParams. (A Client Component instead uses the useSearchParams() hook.)
    • B.Call useSearchParams() — hooks work in Server Components
    • C.Import searchParams from next/navigation
    • D.Parse window.location.search
    Show answer

    Answer: A. A Server Component receives searchParams as a prop. In Next.js 15 it is a Promise, so you await it: const { category } = await searchParams. (A Client Component instead uses the useSearchParams() hook.)

    Page components get params and searchParams as props. Since Next.js 15 both are Promises, resolved with await in the async Server Component. Values are strings (or string[] for a repeated key). Client Components cannot receive these props and use useSearchParams() instead, which returns a URLSearchParams-like object.

    From the quiz API Routes & Middleware

  8. 18.Why does calling cookies() make a route dynamic?

    • A.Cookies are per-user and per-request, so the page's output depends on the specific request — Next.js cannot prerender one static version that is correct for everyone, so it renders the route per request
    • B.It does not — cookies can be read in static routes
    • C.Only in production
    • D.It is a performance choice
    Show answer

    Answer: A. Cookies are per-user and per-request, so the page's output depends on the specific request — Next.js cannot prerender one static version that is correct for everyone, so it renders the route per request

    Static rendering produces one HTML file for all visitors. A page that reads session or theme from cookies would need a different output per user, which a build-time prerender cannot know. So touching cookies() (like headers(), searchParams, or a no-store fetch) marks the route dynamic.

    From the quiz ISR & Revalidation

  9. 19.What is the difference between template.tsx and layout.tsx?

    • A.They are identical — use either
    • B.layout.tsx persists across navigations within its subtree (its state and DOM are preserved); template.tsx creates a new instance on every navigation, so its state resets and its effects re-run each time
    • C.template.tsx is for email templates, not routes
    • D.layout.tsx re-renders from scratch on every navigation
    Show answer

    Answer: B. layout.tsx persists across navigations within its subtree (its state and DOM are preserved); template.tsx creates a new instance on every navigation, so its state resets and its effects re-run each time

    A layout is mounted once and stays mounted as you move between its child routes — ideal for a sidebar or navigation whose state should survive. A template wraps children the same way structurally, but Next.js remounts it on each navigation, giving a fresh component instance. Use a template for per-navigation enter animations, page-view analytics, or resetting form state on route change.

    From the quiz API Routes & Middleware

  10. 20.What is critical when writing Server Actions?

    • A.Server Actions are automatically secured — no checks needed
    • B.Server Actions run client-side, so they are safe by default
    • C.Each "use server" function compiles to a public POST endpoint that anyone can invoke with crafted arguments — so you must validate inputs, verify the session, and check authorization (e.g. that the caller owns the record identified by an ID) inside the action
    • D.Server Actions can only be called by logged-in users automatically
    Show answer

    Answer: C. Each "use server" function compiles to a public POST endpoint that anyone can invoke with crafted arguments — so you must validate inputs, verify the session, and check authorization (e.g. that the caller owns the record identified by an ID) inside the action

    A Server Action is a network-reachable endpoint identified by an opaque ID. Next.js adds Origin checks (CSRF mitigation) but knows nothing about your authorization rules. Treat every action like an API route: parse and validate arguments, resolve the current user, and confirm permissions against the specific resource before mutating.

    From the quiz ISR & Revalidation

Senior level Next.js questions

  1. 21.What is opengraph-image.tsx for?

    javascript
    app/opengraph-image.tsx
    app/blog/[slug]/opengraph-image.tsx
    • A.It renders the page content with an OpenGraph theme
    • B.It replaces metadata.openGraph.images entirely
    • C.It only works at the root route
    • D.It is a file convention that produces the route's og:image: export size/contentType and a default component that returns an ImageResponse (JSX rendered to an image on the server). It can be a static asset or generated per route using params, and Next.js wires the resulting URL into <head> automatically
    Show answer

    Answer: D. It is a file convention that produces the route's og:image: export size/contentType and a default component that returns an ImageResponse (JSX rendered to an image on the server). It can be a static asset or generated per route using params, and Next.js wires the resulting URL into <head> automatically

    Placing an opengraph-image file in a segment makes Next.js generate that image and add the corresponding <meta property="og:image"> for the route. The dynamic form receives params, so /blog/[slug]/opengraph-image.tsx can render a per-post card. ImageResponse (from next/og) renders JSX with a limited CSS subset (mostly flexbox) using a Satori-based engine.

    From the quiz App Router

  2. 22.Are Server Actions vulnerable to CSRF?

    • A.Yes — anyone can POST to a Server Action from any origin
    • B.CSRF only applies to GET, so POST-based Server Actions are inherently safe
    • C.You must add CSRF tokens to every Server Action manually
    • D.Next.js mitigates CSRF automatically: it verifies the request's Origin matches the deployment host and identifies each action by a non-guessable, build-time-hashed ID that is not exposed in a forgeable way. You still must authenticate and authorise inside the action
    Show answer

    Answer: D. Next.js mitigates CSRF automatically: it verifies the request's Origin matches the deployment host and identifies each action by a non-guessable, build-time-hashed ID that is not exposed in a forgeable way. You still must authenticate and authorise inside the action

    Server Actions are POST endpoints, so a malicious page could try to trigger one in a logged-in user's browser. Next.js checks Origin/Host and rejects cross-site invocations, and the opaque action ID prevents an attacker from constructing a valid call blindly. Legitimate cross-origin setups are allowlisted via serverActions.allowedOrigins.

    From the quiz Streaming & Suspense

  3. 23.How do you generate a dynamic sitemap.xml in the App Router?

    • A.Commit a static public/sitemap.xml
    • B.Create app/sitemap.ts exporting a default async function that returns an array of URL entries ({ url, lastModified, changeFrequency, priority }); Next.js serves it at /sitemap.xml
    • C.Configure sitemap paths in next.config.ts
    • D.Install a third-party sitemap package
    Show answer

    Answer: B. Create app/sitemap.ts exporting a default async function that returns an array of URL entries ({ url, lastModified, changeFrequency, priority }); Next.js serves it at /sitemap.xml

    app/sitemap.ts is a built-in metadata route. Its default export can await data (e.g. all published slugs from the database) and return typed MetadataRoute.Sitemap entries; Next.js renders the XML and serves it at the conventional URL. No external tooling is needed.

    From the quiz App Router

  4. 24.What is the difference between export const revalidate = 0 and export const dynamic = 'force-dynamic'?

    • A.They are identical in every respect
    • B.Both produce per-request rendering with no caching, but express different intent: revalidate = 0 is data-layer language ("cached data is immediately stale"), while force-dynamic is rendering-layer language ("always render fresh") and also guarantees cookies()/headers() are treated as available. In practice they behave the same for most routes
    • C.revalidate = 0 only affects fetch calls; force-dynamic affects the whole route
    • D.Only force-dynamic prevents static rendering
    Show answer

    Answer: B. Both produce per-request rendering with no caching, but express different intent: revalidate = 0 is data-layer language ("cached data is immediately stale"), while force-dynamic is rendering-layer language ("always render fresh") and also guarantees cookies()/headers() are treated as available. In practice they behave the same for most routes

    Both make the route dynamic. revalidate = 0 sets the ISR window to zero; force-dynamic explicitly opts the route out of prerendering. The end result — a fresh render per request — is the same for typical use.

    From the quiz Streaming & Suspense

  5. 25.What are headers() and cookies() from next/headers used for?

    • A.headers() returns the incoming request headers and cookies() reads (and, in Server Actions / Route Handlers, writes) cookies. In Next.js 15 both are async, so you await them. Using either opts the route into dynamic rendering, since the values are per-request
    • B.They are browser APIs available in every component
    • C.cookies() can only read, never set
    • D.They only work in Route Handlers
    Show answer

    Answer: A. headers() returns the incoming request headers and cookies() reads (and, in Server Actions / Route Handlers, writes) cookies. In Next.js 15 both are async, so you await them. Using either opts the route into dynamic rendering, since the values are per-request

    These are server-only request APIs. Reads are allowed during rendering (and mark the route dynamic); cookie writes are only valid where Next.js controls the response headers — Server Actions and Route Handlers — not mid-render. Since Next.js 15 the functions return Promises, so it is const store = await cookies().

    From the quiz App Router

  6. 26.How do error boundaries interact with Suspense for a section of a page?

    javascript
    <ErrorBoundary fallback={<ErrorFallback />}>
      <Suspense fallback={<Skeleton />}>
        <DataComponent />
      </Suspense>
    </ErrorBoundary>
    • A.ErrorBoundary is built into Next.js and needs no import
    • B.You cannot use them together
    • C.error.tsx replaces ErrorBoundary entirely — never use one directly
    • D.They compose independently: Suspense handles the pending/loading state (shows the skeleton while <DataComponent /> streams), and the error boundary catches an error thrown during that component's render or data fetch (shows the error fallback). error.tsx is the automatic segment-level version; a component ErrorBoundary (a Client Component) isolates a smaller region
    Show answer

    Answer: D. They compose independently: Suspense handles the pending/loading state (shows the skeleton while <DataComponent /> streams), and the error boundary catches an error thrown during that component's render or data fetch (shows the error fallback). error.tsx is the automatic segment-level version; a component ErrorBoundary (a Client Component) isolates a smaller region

    Suspense and error boundaries solve different problems and nest cleanly. Wrap a section's async component in <Suspense> for its skeleton and in an ErrorBoundary (class-based, or react-error-boundary) so a failure there does not take down the whole page. The route-level error.tsx is the coarse fallback above them.

    From the quiz Streaming & Suspense

  7. 27.What is Turbopack?

    javascript
    next dev --turbopack
    • A.It is only available on Vercel's platform
    • B.It is deprecated in Next.js 15
    • C.A Rust-based bundler that replaces Webpack in Next.js: it is stable for next dev (much faster cold start and Hot Module Replacement, lower memory), and production builds via next build --turbopack are now available as the toolchain stabilises
    • D.It replaces both Webpack and Vite everywhere, immediately, with no caveats
    Show answer

    Answer: C. A Rust-based bundler that replaces Webpack in Next.js: it is stable for next dev (much faster cold start and Hot Module Replacement, lower memory), and production builds via next build --turbopack are now available as the toolchain stabilises

    Turbopack is Next.js's incremental bundler written in Rust. It recompiles only what changed with fine-grained caching, which makes large-project dev startup and HMR dramatically faster than Webpack. Development use is stable; production builds with Turbopack have been rolling out and reaching stability, though some Webpack plugins and edge cases are still catching up.

    From the quiz App Router

  8. 28.What is the route's effective behaviour?

    javascript
    export const revalidate = 3600;
    const a = await fetch('/api/a', { next: { revalidate: 60 } });
    const b = await fetch('/api/b', { next: { revalidate: 86400 } });
    const c = await fetch('/api/c', { cache: 'no-store' });
    • A.Each fetch revalidates fully independently with no route-level effect
    • B.The segment-level revalidate: 3600 overrides all per-fetch settings
    • C.The highest value (86400) is used for stability
    • D.Among cached fetches the lowest revalidate wins for the route's regeneration cadence (here 60s); the segment revalidate is the default for fetches that do not specify one; and the single cache: 'no-store' fetch makes the whole route dynamic, overriding the caching entirely
    Show answer

    Answer: D. Among cached fetches the lowest revalidate wins for the route's regeneration cadence (here 60s); the segment revalidate is the default for fetches that do not specify one; and the single cache: 'no-store' fetch makes the whole route dynamic, overriding the caching entirely

    Per-fetch options override the segment default. The routes revalidation is effectively the minimum of the cached fetches windows, so stale data is never served longer than the most frequently-updated dependency allows. But any no-store (or revalidate: 0) fetch anywhere in the render opts the route out of static rendering.

    From the quiz Streaming & Suspense

  9. 29.What does after() from next/server do?

    javascript
    import { after } from 'next/server';
    
    export async function POST(request: Request) {
      const user = await createUser(await request.json());
      after(async () => { await sendWelcomeEmail(user.email); });
      return Response.json({ id: user.id }, { status: 201 });
    }
    • A.It delays the response by a number of milliseconds
    • B.It is equivalent to setTimeout
    • C.It only works in Client Components
    • D.It schedules a callback to run after the response has finished streaming to the client, so non-blocking side effects (analytics, emails, cache warming, revalidation) do not add latency to the user's request — while still executing within the same server invocation
    Show answer

    Answer: D. It schedules a callback to run after the response has finished streaming to the client, so non-blocking side effects (analytics, emails, cache warming, revalidation) do not add latency to the user's request — while still executing within the same server invocation

    after() registers post-response work. The user gets their response immediately; the callback runs afterward on the server (important on serverless platforms, where the function would otherwise be frozen). It is for best-effort side effects, not for anything the response's correctness depends on.

    From the quiz App Router

  10. 30.What is the correct pattern?

    javascript
    'use client';
    function TodoList({ initialTodos }: { initialTodos: Todo[] }) {
      // implement optimistic delete
    }
    • A.Track todos in useState and call the Server Action directly
    • B.Delete client-side first, then sync to the server in a useEffect
    • C.Call useOptimistic(initialTodos, (todos, deletedId) => todos.filter(t => t.id !== deletedId)); in a transition, apply the optimistic removal then await deleteTodoAction(id). React shows the item gone immediately; once the action settles and the parent re-renders with fresh data, the optimistic layer is dropped (so revalidate on the server, or the item reappears)
    • D.useOptimistic can only add items, not remove them
    Show answer

    Answer: C. Call useOptimistic(initialTodos, (todos, deletedId) => todos.filter(t => t.id !== deletedId)); in a transition, apply the optimistic removal then await deleteTodoAction(id). React shows the item gone immediately; once the action settles and the parent re-renders with fresh data, the optimistic layer is dropped (so revalidate on the server, or the item reappears)

    useOptimistic's reducer can express any transition, including a filter for delete. Call the updater inside startTransition (or the form action), run the Server Action, and have that action call revalidatePath/revalidateTag so initialTodos updates. When it does, the optimistic layer clears and the real state — now without the item — takes over.

    From the quiz Streaming & Suspense

Practise 200+ more Next.js questions

Timed quizzes with instant feedback, the questions you miss coming back until they stick, coding challenges and AI mock interviews — free to start.