A Next.js developer builds SEO-friendly, fast web apps using the Next.js App Router, React Server Components, server-side rendering and static generation. They decide rendering strategies per page, handle caching and revalidation, write Server Functions for mutations and optimise Core Web Vitals. Demand is strong in e-commerce, content, fintech and SaaS companies where search traffic and load speed directly affect business.
Next.js App Router Server Components SSR, SSG and ISR SEO and metadata Caching and revalidation
Solved for this roleStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
✓ 3 questions free • Unlock the rest in seconds
01
During a security review you find a payment provider's secret key in the browser's JavaScript bundle. What do you do?
Treat it as leaked: rotate the key immediately in the provider dashboard and check logs for misuse. Then fix the cause, usually the secret was in a public env variable such as NEXT_PUBLIC_ or VITE_, or imported into a client component. Move the call to a server route or Server Function that uses a server-only variable, add the server-only package to guard imports, and add secret scanning in CI.
02
How do you set SEO metadata in a Next.js App Router page?
Export a metadata object or a generateMetadata function from a page or layout.
export async function generateMetadata({ params }) {
const { slug } = await params;
const post = await getPost(slug);
return {
title: post.title,
description: post.summary,
alternates: { canonical: `/blog/${slug}` },
openGraph: { title: post.title, images: [post.cover] }
};
}
Next.js renders the tags in the head during server rendering.
03
What is the difference between server state and client state?
Client state is owned by the browser, like whether a modal is open, form input or theme. Server state lives on a backend and is only cached on the client, like products or orders; it can become stale, be changed by other users and needs refetching. Tools like TanStack Query or RTK Query manage server state, while useState, Context or Zustand handle client state.
Zustand is a small state library with a hook-based API and no Provider.
import { create } from 'zustand';
const useCart = create(set => ({
items: [],
add: item => set(s => ({ items: [...s.items, item] })),
clear: () => set({ items: [] })
}));
const count = useCart(s => s.items.length);
Components subscribe with selectors, so they re-render only when the selected slice changes.
05
Tell me about a time a requirement changed late in a sprint. How did you handle it?
Situation: two days before release, the product owner asked to add a GST number field with validation to our checkout form. Task: deliver it without risking the release. Action: I estimated the impact, proposed shipping the field with basic format validation first and the full verification API in the next sprint, and added tests. Result: we released on time and the follow-up shipped a week later.
06
After adding an AuthContext at the root, profiling shows the whole app re-rendering every few seconds. What would you check?
Check what the provider value is and what updates it. Likely the value is a new object each render, or it includes fast-changing data such as a token refresh timer or a clock. Memoise the value with useMemo, move frequently changing data out of the context, and split it into separate contexts, so components reading only the user do not re-render when unrelated fields change.
Use an i18n library such as react-i18next or, in Next.js, next-intl. Store translations in JSON files per locale, reference keys like t('cart.title') instead of hard-coded text, and handle plurals, dates, numbers and currency with Intl APIs. Put the locale in the URL, like /hi/products, for SEO and shareable links. For Indian audiences, check fonts for Devanagari and other scripts and test longer translated text.
Make the page an async Server Component and await data directly.
// app/products/[id]/page.tsx
export default async function ProductPage({ params }) {
const { id } = await params;
const product = await getProduct(id);
if (!product) notFound();
return (
<main>
<h1>{product.name}</h1>
<AddToCartButton id={id} />
</main>
);
}
AddToCartButton is a Client Component. In recent Next.js versions params is a promise.
10
What are memoised selectors and why use createSelector?
A selector reads or derives data from the store. If a selector returns a new array each time, such as state.todos.filter(t => t.done), useSelector sees a new reference and re-renders on every store update. createSelector from Reselect, included in Redux Toolkit, caches the result and recomputes only when its input selectors return changed values, avoiding wasted renders and repeated expensive calculations.
Server Components run only on the server or at build time. They can be async, read databases or files directly and send rendered output to the client without shipping their JavaScript, which reduces bundle size. They cannot use state, effects or browser APIs. Client Components, marked with 'use client', handle interactivity. Server Components can render Client Components and pass them serialisable props.
Use the React DevTools Profiler: record an interaction, then check the flame chart for components with long render times and the reason each one re-rendered (enable 'record why each component rendered'). Pair it with the Chrome Performance panel for long tasks, layout and network. Enable highlight updates to spot unnecessary renders. Measure first, fix the biggest cost, then measure again in a production build.
13
What do useActionState and useFormStatus do in React 19?
useActionState wraps an action function and returns [state, formAction, isPending]; you pass formAction to a form's action prop and the returned state holds the result, like a validation error. useFormStatus, from react-dom, lets a child component such as a submit button read the pending status of the parent form without prop drilling. Together they remove a lot of manual loading and error state code.
14
Tell me about a time you pushed back on adding a new library to the project.
Situation: a teammate proposed adding Redux to a small admin app. Task: decide whether it was worth the added complexity. Action: I listed our actual shared state, which was just the user and a few filters, and showed a prototype using TanStack Query for API data and one small context. Result: we shipped faster with less code, and agreed to revisit if requirements grew.
RTK Query is the data fetching and caching tool included in Redux Toolkit. You define an API with createApi and endpoints, and it auto-generates hooks like useGetProductsQuery and useAddProductMutation. It handles loading states, caching, deduplicating requests, refetching and cache invalidation through tags. It removes most hand-written thunks and reducers for server data in Redux-based apps.
16
An orders table renders 10,000 rows and the page freezes on load and scroll. What would you do?
First question whether users need all rows at once: server-side pagination or infinite scroll with cursor-based loading may solve it. If a long scrollable list is required, virtualise it with TanStack Virtual so only around 30 rows exist in the DOM. Also memoise row components, avoid heavy formatting in render by precomputing, and move sorting or filtering off the main thread if it is expensive.
CSR (client-side rendering) sends a minimal HTML shell and renders everything in the browser. SSR (server-side rendering) generates HTML on each request, good for personalised or fast-changing pages. SSG (static site generation) builds HTML at build time, fastest for pages that rarely change like blogs. ISR (incremental static regeneration) serves static pages but regenerates them in the background after a time or on demand, mixing speed with freshness.
18
How would you implement an optimistic update with TanStack Query and roll back on failure?
In useMutation, use onMutate to cancel ongoing queries, save the previous cache data and update the cache with the expected result. In onError, restore the saved snapshot and show an error toast. In onSettled, invalidate the query so the cache syncs with the server. This makes actions like toggling a favourite feel instant while keeping data correct if the server rejects the change.
19
Tell me about a time you improved the performance of an application.
Situation: our admin dashboard took about eight seconds to become usable on office laptops. Task: bring it under three seconds. Action: I profiled it, found a 2 MB bundle and a chart library loaded on every page, lazy loaded routes and charts, replaced moment with dayjs and virtualised a large table. Result: load time dropped to around 2.5 seconds and support complaints about slowness stopped.
20
What is the main performance pitfall of React Context and how do you avoid it?
Every component that reads a context re-renders when the provider value changes. If you pass a new object like value={{ user, setUser }} on each render, all consumers re-render even if nothing changed. Memoise the value with useMemo, split one big context into smaller ones (for example state and dispatch separately), and keep fast-changing data in a dedicated store like Zustand that supports selectors.
21
Five components on one page each fetch the same user profile, causing duplicate API calls. How would you fix this?
Lift the data fetching into a shared cache instead of each component fetching on its own. With TanStack Query or RTK Query, all components using the same query key share one request and one cached result, and get updates together. Alternatively, fetch once in a parent or route loader and pass data down. This also removes inconsistent loading spinners across the page.
22
Tell me about working with a backend team when an API did not match what the frontend needed.
Situation: the orders API returned deeply nested data and no pagination, making our list screen slow. Task: get a better contract without blocking either team. Action: I shared a proposed response shape with the backend developer, explained the performance impact with numbers and built against a mocked API using MSW meanwhile. Result: they added pagination and flatter fields, and we integrated in two days with no rework.
23
How do you test a component that fetches data from an API?
Virtualisation, or windowing, renders only the rows visible in the viewport plus a small buffer, instead of thousands of DOM nodes. As the user scrolls, rows are recycled with new data. Libraries such as TanStack Virtual and react-window implement it. It dramatically cuts render time and memory for long lists, chat histories and data grids, but needs care with variable row heights and browser find-in-page.
25
How does a child component send data back to its parent?
The parent passes a callback function as a prop, and the child calls it with the data.
function Parent() {
const [city, setCity] = useState('');
return <CityPicker onSelect={setCity} />;
}
function CityPicker({ onSelect }) {
return (
<select onChange={e => onSelect(e.target.value)}>
<option>Delhi</option>
<option>Noida</option>
</select>
);
}
'use client' at the top of a file marks a boundary: that module and everything it imports become part of the client bundle and can use state, effects, event handlers and browser APIs. It does not mean the component is only rendered on the client; it is still pre-rendered to HTML on the server and then hydrated. Keep 'use client' as low in the tree as possible to send less JavaScript.
27
A blog feature must render HTML content that comes from a CMS. Why is dangerouslySetInnerHTML risky and how do you use it safely?
React escapes values in JSX by default, which protects against XSS. dangerouslySetInnerHTML bypasses this and inserts raw HTML, so if the content comes from users or an untrusted CMS, attackers can inject scripts. If you must render HTML, sanitise it first with a library like DOMPurify, restrict allowed tags, and add a Content Security Policy. Also never put user input into href attributes without validating the protocol.
Flux is the unidirectional data flow pattern that inspired Redux. Actions describe events, a dispatcher sends them to stores, stores update data and notify views, and views render and trigger new actions. Data never flows backward directly. Redux simplified Flux into a single store with pure reducers. Understanding Flux explains why React state management favours one-way flow over two-way binding.
29
Where should you store the logged-in user's auth token in a React app?
The safest common choice is an httpOnly, Secure, SameSite cookie set by the server, because JavaScript cannot read it, which protects it from XSS theft. Keep only non-sensitive user info, such as name and role, in React state or context. If you must use tokens in JavaScript, keep the access token in memory, use short expiry and refresh tokens via cookies. Avoid localStorage for tokens.
30
A new mid-sized dashboard project is starting. How would you decide between Context, Redux Toolkit and Zustand?
First separate server state, which I would handle with TanStack Query or RTK Query. For remaining client state, local useState covers most needs. Context suits rarely changing values like theme or auth. If there is complex shared state with many actions, strict patterns, large teams and need for DevTools time travel, Redux Toolkit fits. For simpler shared state with less boilerplate, Zustand is a good choice.
Disabling it usually hides a stale closure bug. The rule tells you the effect reads a value that can change. Instead, include the dependency, move a function inside the effect, use the updater form of setState so state is not needed, or move non-reactive logic into useEffectEvent. If an object dependency changes every render, create it inside the effect or memoise it. Suppress only with a clear comment.
Tree shaking is dead code elimination done by bundlers like Rollup (used by Vite), esbuild and webpack. They analyse ES module import and export statements and drop exports that are never used. It works only with static ESM syntax, not CommonJS require, and can be blocked by modules with side effects. Importing import { debounce } from 'lodash-es' instead of the whole lodash library keeps the bundle small.
Middleware sits between dispatching an action and the reducer, letting you intercept actions for side effects. Signature: store => next => action => {...}. Common uses are async logic (redux-thunk, included by default in Redux Toolkit), logging, analytics, error reporting and the RTK Query cache middleware. Redux Toolkit also provides listenerMiddleware for reacting to actions, a lighter alternative to redux-saga for most cases.
35
A developer writes key={Math.random()} to silence the missing key warning. What problem does this create?
A new random key on every render tells React each item is brand new, so it unmounts and remounts every row each time. This destroys component state such as typed input and focus, re-runs effects and is very slow for large lists. Keys must be stable and unique, ideally an id from the data. If items have no id, generate ids once when the data is created.
Install the Redux DevTools browser extension; configureStore enables it automatically in development. You can see every dispatched action, the state before and after, the diff, and jump back in time to earlier states. Check whether the expected action was dispatched, whether its payload is correct and whether the reducer updated the right slice. For selectors, log their output or use the React DevTools profiler.
37
A teammate wraps every function in useCallback and every value in useMemo for performance. When should you not memoise, and what feedback would you give?
Memoisation has costs: extra memory, comparisons on every render and more complex code. Skip it for cheap calculations, components that rarely re-render, and props that change every render anyway. Memoising everything by default also hides design problems like state placed too high. Use the profiler to find real bottlenecks first. With the React Compiler, manual memoisation is mostly needed only as an escape hatch.
38
What are micro-frontends and when are they worth it?
Micro-frontends split a large web app into independently built and deployed parts owned by different teams, for example search, cart and account, combined at runtime using Module Federation, iframes or route-level composition. They help very large organisations scale teams and deployments. The costs are duplicated dependencies, harder shared state, inconsistent UX and complex tooling, so they are rarely worth it for small or medium teams.
39
Show a Server Function used to handle a form in Next.js.
A function marked 'use server' runs on the server and can be passed to a form action.
// app/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
export async function addTodo(formData: FormData) {
const title = String(formData.get('title'));
await db.todo.create({ data: { title } });
revalidatePath('/todos');
}
// app/todos/page.tsx
<form action={addTodo}>
<input name="title" required />
<button>Add</button>
</form>
Always validate input and check authorisation inside the function.
40
Your Next.js build fails with 'ReferenceError: window is not defined'. Why, and how do you fix it?
Code that touches browser globals runs during server rendering, where window and document do not exist. This often comes from a library that accesses window at import time or from reading localStorage in render. Fix it by moving browser access into useEffect or event handlers inside a Client Component, checking typeof window !== 'undefined', or loading the library with next/dynamic and ssr: false from a client component.
Frequently asked questions
What does a Next.js Developer do?
A Next.js developer builds SEO-friendly, fast web apps using the Next.js App Router, React Server Components, server-side rendering and static generation. They decide rendering strategies per page, handle caching and revalidation, write Server Functions for mutations and optimise Core Web Vitals. Demand is strong in e-commerce, content, fintech and SaaS companies where search traffic and load speed directly affect business.
Which skills are tested in a Next.js Developer interview?
Expect questions on Next.js App Router, Server Components, SSR, SSG and ISR, SEO and metadata, Caching and revalidation. Most rounds also ask you to explain a project and solve one practical problem live.
How do I prepare for a Next.js Developer interview?
Revise Next.js and Advanced React, Performance Optimization, State Management first using the topic sheets, practise the questions on this page aloud, then do one full mock interview to practise timing.