Most Next.js interview question banks (this one included) were written for the Pages Router era — getStaticProps, getServerSideProps, pages/api. The App Router (stable since Next 13, and what current Next.js projects — including this site — actually build on) replaced most of that with Server Components and a different data-fetching model. This covers every question as asked, with the Pages Router API explained accurately, and the current App Router equivalent noted alongside it so the answer is useful either way.
Next.js Fundamentals
Q1. What is Next.js and what are its main features?
Next.js is a React framework adding the pieces a production app needs beyond bare React — routing, server-side rendering, static generation, API endpoints, image optimization, and a build/deploy pipeline, all with sensible defaults instead of hand-assembling them from separate libraries. Its core value proposition has stayed consistent even as the underlying implementation (Pages Router → App Router) changed significantly.
Q2. How does Next.js differ from Create React App?
| Create React App | Next.js | |
|---|---|---|
| Rendering | Client-side only (a single index.html + JS bundle) | Server-side rendering, static generation, and client-side, per-route |
| Routing | You add a router yourself (React Router) | Built in — file-based, no extra library needed |
| Status | Officially deprecated by the React team | Actively developed, one of the React team's recommended frameworks |
Q3. What command is used to create a new Next.js app?
npx create-next-app@latest my-app
cd my-app
npm run devQ4. How does Next.js handle server-side rendering (SSR)?
// Pages Router — re-runs on every request
export async function getServerSideProps() {
const data = await fetchData();
return { props: { data } };
}
// App Router — a Server Component fetches directly, no special export needed
export default async function Page() {
const data = await fetchData();
return <div>{data.title}</div>;
}In the Pages Router, getServerSideProps runs on the server for every request and its returned props hydrate the page. In the App Router, Server Components fetch data directly inside the component itself (just an async function component) — Next.js decides whether to render it dynamically per-request or statically at build time based on how the data is fetched, without a separate special-named export.
Q5. Can you explain the purpose of the pages directory in a Next.js project?
In the Pages Router, every file under pages/ automatically becomes a route — pages/about.js is /about, pages/blog/[slug].js is a dynamic /blog/:slug route. The App Router replaces this with an app/ directory using folders (not files) as route segments, each containing a page.js — the same file-system-as-routing philosophy, restructured.
Q6. In Next.js, how do you create a page that is rendered on the server for every request?
// Pages Router
export async function getServerSideProps(context) {
return { props: { time: new Date().toISOString() } };
}
// App Router — opt out of caching to force per-request rendering
export const dynamic = "force-dynamic";
export default async function Page() {
const time = new Date().toISOString();
return <div>{time}</div>;
}Q7. What file extensions does Next.js support for pages?
.js, .jsx, .ts, and .tsx — TypeScript support is built in with zero extra configuration; Next.js auto-detects a tsconfig.json (or creates one) and handles the compilation itself.
Q8. How do environment variables work in Next.js?
# .env.local
DATABASE_URL=postgres://...
NEXT_PUBLIC_API_URL=https://api.example.comVariables in .env.local are available server-side automatically; only variables explicitly prefixed with NEXT_PUBLIC_ are also inlined into the client-side JS bundle at build time. This prefix requirement is a deliberate safety rail — it's much harder to accidentally leak a secret (a database URL, an API key) into the browser bundle than if all env vars were exposed by default.
Q9. What is Automatic Static Optimization in Next.js?
In the Pages Router, a page with no getServerSideProps/getInitialProps is automatically pre-rendered to static HTML at build time — zero configuration required to get a fast, CDN-cacheable page. The App Router carries the same philosophy forward as its default: a route is statically rendered at build time unless something in it (a dynamic data fetch, force-dynamic) requires per-request rendering.
Pages and Routing
Q10. How does file-based routing work in Next.js?
| File path | Pages Router route | App Router equivalent |
|---|---|---|
| index.js | / | app/page.js |
| about.js | /about | app/about/page.js |
| blog/[slug].js | /blog/:slug | app/blog/[slug]/page.js |
In both routers, the file system directly defines the route structure — no separate route-configuration file to maintain in sync with the actual pages, unlike a traditional SPA router where routes are declared in code separately from the components they render.
Q11. How do you create dynamic routes in Next.js?
// Pages Router: pages/blog/[slug].js
// App Router: app/blog/[slug]/page.js
export default function BlogPost({ params }) {
return <h1>{params.slug}</h1>;
}Square brackets in a file/folder name ([slug]) mark a dynamic segment — [...slug] (Pages Router) or [...slug] as a folder (App Router) captures a catch-all of multiple path segments instead of just one.
Q12. Explain how to access URL parameters in a dynamic route.
// Pages Router
import { useRouter } from "next/router";
const router = useRouter();
const { slug } = router.query;
// App Router — params passed directly to the page component
export default function Page({ params }) {
return <div>{params.slug}</div>;
}Q13. Describe the functionality of the Link component in Next.js.
import Link from "next/link";
<Link href="/about">About</Link>Link renders a real, crawlable <a> tag but intercepts the click for client-side navigation — no full page reload, and Next.js automatically prefetches the linked page's data/code in the background when the link enters the viewport, so navigation feels instant when the user actually clicks it.
Q14. How do you handle catch-all routes in Next.js?
// pages/docs/[...slug].js or app/docs/[...slug]/page.js
// Matches /docs/a, /docs/a/b, /docs/a/b/c — params.slug is an array: ['a','b','c']
// Optional catch-all — [[...slug]] — also matches /docs itself with an empty arrayData Fetching and Rendering
Q15. What is getStaticProps and when would you use it?
// Pages Router — runs at build time, produces static HTML
export async function getStaticProps() {
const posts = await fetchPosts();
return { props: { posts } };
}
// App Router equivalent — a Server Component, statically rendered by default
export default async function Page() {
const posts = await fetchPosts();
return <PostList posts={posts} />;
}getStaticProps runs once at build time (or on-demand with ISR, covered next), pre-rendering the page to static HTML — ideal for content that doesn't need to be fresh on every single request (blog posts, marketing pages, product listings that update periodically).
Q16. What is getServerSideProps and what kind of rendering does it enable?
Covered above under Fundamentals — it enables true per-request server-side rendering, for pages whose content genuinely must reflect the exact moment of the request (a personalized dashboard, real-time pricing) rather than a build-time or periodically-revalidated snapshot.
Q17. How would you implement Incremental Static Regeneration (ISR) in Next.js?
// Pages Router
export async function getStaticProps() {
const posts = await fetchPosts();
return { props: { posts }, revalidate: 60 }; // regenerate at most once every 60s
}
// App Router — the same idea, via fetch's own caching option
export default async function Page() {
const res = await fetch("https://api.example.com/posts", { next: { revalidate: 60 } });
const posts = await res.json();
return <PostList posts={posts} />;
}ISR serves the existing static page instantly while regenerating it in the background once the revalidate window has passed — visitors always get a fast, cached response, and the content still stays reasonably fresh without a full rebuild/redeploy for every content change.
Q18. Can you use client-side data fetching in Next.js? If so, how?
"use client";
import useSWR from "swr";
function Profile() {
const { data, error } = useSWR("/api/user", fetcher);
if (error) return <div>Failed to load</div>;
return <div>{data?.name}</div>;
}Yes — plain useEffect + fetch, or (more commonly) a data-fetching library like SWR or TanStack Query that adds caching, revalidation, and loading/error states. Client-side fetching fits data that's genuinely user/session-specific and doesn't need to be part of the initial server-rendered HTML.
Q19. Explain the 'fallback' key used in the getStaticPaths function.
export async function getStaticPaths() {
return { paths: [{ params: { slug: "hello-world" } }], fallback: "blocking" };
}| fallback value | Behavior for a path not pre-rendered at build time |
|---|---|
| false | Returns a 404 immediately |
| true | Serves a fallback/loading state instantly, generates the real page in the background |
| 'blocking' | Server-renders the page on that first request (like SSR), caches it as static after |
getStaticPaths (Pages Router) declares which dynamic-route paths to pre-render at build time; fallback controls what happens for a path not in that list — the App Router achieves the same effect with generateStaticParams plus dynamicParams, following the same underlying trade-off between build-time coverage and on-demand generation.
API Routes
Q20. How do you create an API route in Next.js?
// Pages Router: pages/api/products.js
export default function handler(req, res) {
res.status(200).json({ products: [] });
}
// App Router: app/api/products/route.js
export async function GET(request) {
return Response.json({ products: [] });
}Any file under pages/api/ (Pages Router) or a route.js exporting a named HTTP-verb function under app/ (App Router, called "Route Handlers") becomes a serverless API endpoint — no separate backend server needed for simple API needs alongside the frontend.
Q21. Can you use middleware within Next.js API routes?
// middleware.js — runs before the request reaches a route/page
export function middleware(request) {
const token = request.cookies.get("session");
if (!token) return NextResponse.redirect(new URL("/login", request.url));
return NextResponse.next();
}
export const config = { matcher: "/dashboard/:path*" };Next.js Middleware runs before a request reaches any route (page or API route) matching its configured paths — for cross-cutting concerns like auth checks, redirects, or header manipulation applied once, rather than duplicated at the top of every individual API route handler.
Q22. Explain how to handle query parameters in Next.js API routes.
// Pages Router
export default function handler(req, res) {
const { category } = req.query;
}
// App Router
export async function GET(request) {
const { searchParams } = new URL(request.url);
const category = searchParams.get("category");
}Styling in Next.js
Q23. How can you include CSS modules in your Next.js application?
// styles.module.css
.button { color: blue; }
// Component.jsx
import styles from "./styles.module.css";
<button className={styles.button}>Click</button>Any file named *.module.css is automatically scoped locally — the class names are hashed at build time so styles.button never leaks into or collides with another component's identically-named class, with zero extra configuration beyond the file naming convention.
Q24. Compare and contrast CSS-in-JS and styled-components in the context of Next.js.
| CSS Modules | styled-components (CSS-in-JS) | |
|---|---|---|
| Where styles live | Separate .css files | Inside the JS/component file itself |
| App Router support | Works out of the box | Needs extra setup for Server Component compatibility |
| Dynamic styling based on props | Requires conditional className logic | Native — styles can reference props directly |
CSS-in-JS libraries generally rely on client-side JavaScript to inject styles, which is in tension with the App Router's Server Components (which render with no client JS runtime at all) — this is exactly why Tailwind CSS and CSS Modules (both fully static, no runtime JS needed) have become the more common choice for new App Router projects.
Q25. Can global styles be used in Next.js? If so, how?
// Pages Router: imported once in pages/_app.js
// App Router: imported once in app/layout.js
import "./globals.css";Performance Optimization
Q26. What is the Image component and how does it help optimize performance in Next.js?
import Image from "next/image";
<Image src="/photo.jpg" width={800} height={600} alt="A photo" priority />next/image automatically serves correctly-sized, modern-format (WebP/AVIF) images, lazy-loads anything below the fold by default, and prevents layout shift by reserving space based on the declared width/height — all without you hand-rolling responsive srcset markup or a separate image CDN integration.
Q27. How does code splitting work in Next.js?
Every page automatically gets its own JS bundle, so a visitor loading /about never downloads the code for /checkout — on top of that, next/dynamic lets you lazy-load a specific component only when it's actually needed (a modal, a heavy chart library), splitting the bundle even further within a single page.
Q28. What are the methods provided by Next.js for prefetching pages?
Link components automatically prefetch the linked page's code/data once they enter the viewport (in production builds) — this is on by default and can be disabled per-link with prefetch={false} for links that are unlikely to actually be clicked, avoiding wasted bandwidth.
Deployment and Hosting
Q29. What are the benefits of deploying a Next.js application to Vercel?
Vercel is Next.js's creator, so it's the most tightly integrated hosting target — zero-config support for ISR, Edge Middleware, image optimization, and preview deployments per pull request, all working exactly as designed without extra adapter configuration a third-party host would need.
Q30. How do you configure custom domain names when deploying a Next.js application?
On Vercel: add the domain in the project's dashboard and update your DNS records (a CNAME or A record) as instructed — Vercel handles SSL certificate provisioning automatically. Other hosts follow the same general pattern: point DNS at the host, configure the domain in that host's settings.
Q31. Explain how to deploy a Next.js app using a different hosting service, such as AWS or Netlify.
npm run build
npm run start # runs the production Node.js server, for a traditional host
# For a fully static export (no server-side features):
# next.config.js: output: 'export'Any Node.js-capable host (AWS via Amplify/EC2/App Runner, Netlify, Railway) can run next build + next start directly, since Next.js's production server is just a Node.js process. For a purely static site with no SSR/ISR/API routes, output: 'export' produces plain static HTML deployable to any static host, including a plain S3 bucket or GitHub Pages.
Integrations and Plugins
Q32. How do you integrate a CSS framework like Tailwind CSS into a Next.js project?
npx create-next-app@latest --tailwind # built-in scaffolding option
# or, in an existing project:
npm install tailwindcss @tailwindcss/postcss postcsscreate-next-app has a built-in --tailwind flag that scaffolds the entire setup; for an existing project, installing the package and adding the PostCSS config plus importing Tailwind's directives into your global CSS file is the whole integration.
Q33. What are some popular plugins for Next.js and what functionalities do they add?
| Package | Adds |
|---|---|
| next-seo | Declarative SEO meta tag management |
| next-auth (Auth.js) | Authentication with many providers, session handling |
| next-i18next | Internationalization/localization |
| @next/bundle-analyzer | Visualizing what's actually in your JS bundles |
Q34. How do you enable TypeScript support in a Next.js project?
npx create-next-app@latest --typescript
# or, in an existing JS project, just add a tsconfig.json and rename a file to .tsx —
# Next.js detects it and finishes the setup (installing @types/* deps) automaticallyAdvanced Features
Q35. How do you implement a custom server in Next.js and why would you do so?
A custom Node.js server (using Express or the raw http module) wraps Next.js's request handler for cases needing custom routing logic outside what file-based routing/Middleware can express, or integrating with an existing Express-based backend. It's increasingly rare with the App Router's Middleware and Route Handlers covering most of what custom servers used to be needed for — and it forfeits some hosting-platform-specific optimizations (like Vercel's edge network features).
Q36. What are the considerations when setting up internationalized routing in Next.js?
// next.config.js (Pages Router built-in i18n routing)
module.exports = {
i18n: {
locales: ["en", "fr", "de"],
defaultLocale: "en",
},
};Pages Router has built-in locale-prefixed routing (/fr/about) configured in next.config.js. The App Router has no equivalent built-in feature — internationalized routing there is implemented manually via a [locale] dynamic segment and Middleware detecting/redirecting based on the Accept-Language header, typically paired with a library like next-intl.
Q37. How do you handle custom error pages in a Next.js application?
// Pages Router: pages/404.js, pages/500.js, pages/_error.js
// App Router: app/not-found.js, app/error.js (a Client Component, for error boundaries)Best Practices
Q38. What folder structure is recommended for large-scale Next.js applications?
- Colocate route-specific components inside their route segment folder (app/dashboard/_components/) rather than one giant shared components/ directory
- A dedicated lib/ or src/lib/ for framework-agnostic business logic, separate from UI components
- Feature-based grouping (features/orders/, features/auth/) once the app grows beyond a handful of routes, rather than organizing purely by file type
Q39. How should you structure components in a Next.js application for optimal code reusability?
Keep presentational ("dumb") components free of data-fetching logic so they're reusable across different pages/contexts, push data fetching to the page/Server Component level (or a custom hook, for client components), and default new components to Server Components in the App Router — opting into 'use client' only where actual interactivity requires it.
Q40. What are some security best practices you should follow in a Next.js app?
- Never expose secrets via NEXT_PUBLIC_ env vars — that prefix puts the value directly in the client bundle
- Validate and sanitize all input in API routes/Route Handlers just as rigorously as any other backend
- Set security headers (CSP, X-Frame-Options) via next.config.js or Middleware
- Keep Next.js itself and dependencies patched — framework-level CVEs do occur and get fixed in point releases
State Management in Next.js
Q41. How do you manage global state in a Next.js application without using external libraries?
"use client";
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("dark");
return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>;
}React's built-in Context API (wrapped in a 'use client' provider, then used in layout.js/_app.js) covers most global client-state needs without pulling in Redux/Zustand — appropriate as long as updates aren't so frequent/granular that Context's broad re-render behavior becomes a real performance problem.
Q42. When should you consider using a state management library like Redux in a Next.js project?
When state is genuinely complex (many interrelated pieces, frequent updates across many disconnected components) and Context's coarser re-render granularity starts causing real performance issues, or when you specifically want Redux DevTools' time-travel debugging and middleware ecosystem — for most apps, Context or a lighter library (Zustand, Jotai) is enough.
Q43. Explain how to persist state between page transitions in a Next.js app.
Client-side navigation via Link/useRouter already preserves any state held in a top-level layout/Context provider (it doesn't unmount on navigation) — for state that must survive a full page reload too, persist to localStorage/sessionStorage or the URL's query string, and rehydrate it on mount.
Next.js and TypeScript
Q44. What are the advantages of using TypeScript in a Next.js project?
Compile-time type checking catches a large class of bugs (wrong prop types, typos in a data shape) before runtime, autocomplete/IntelliSense becomes dramatically more useful, and Next.js's own APIs (page props, API route handlers) ship with first-class type definitions that make the framework itself easier to use correctly.
Q45. How do you add type definitions for a Next.js page's props?
// Pages Router
import { GetServerSideProps } from "next";
interface Props { title: string; }
export const getServerSideProps: GetServerSideProps<Props> = async () => {
return { props: { title: "Hello" } };
};
export default function Page({ title }: Props) {
return <h1>{title}</h1>;
}Q46. What steps are involved in migrating an existing Next.js project to TypeScript?
- Add a tsconfig.json (Next.js will offer to create one automatically the next time you run the dev server)
- Rename files incrementally, .js → .tsx / .ts — no need to convert the whole project at once, JS and TS files coexist fine
- Install @types/react and @types/node
- Fix type errors surfaced file by file as you go, rather than all at once
Q47. Can you describe how to use TypeScript for defining API route handlers in Next.js?
// Pages Router
import type { NextApiRequest, NextApiResponse } from "next";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ ok: true });
}
// App Router — Web-standard Request/Response types, no Next-specific typing needed
export async function GET(request: Request) {
return Response.json({ ok: true });
}Q48. How do you enforce type checking for dynamic routes in Next.js using TypeScript?
// App Router
interface PageProps {
params: { slug: string };
}
export default function Page({ params }: PageProps) {
return <div>{params.slug}</div>;
}Q49. How does Next.js handle automatic type generation for pages and API routes when using TypeScript?
Next.js generates a next-env.d.ts file (referencing the framework's own ambient types) automatically on first run — beyond that, page/route prop types (GetServerSideProps<T>, the Route Handler's Request/Response) come from Next.js's own published type definitions, not generated per-project; you still explicitly type your own props/params.
Q50. What is the role of the tsconfig.json file in a Next.js project with TypeScript, and how do you customize it for your specific needs?
{
"compilerOptions": {
"strict": true,
"paths": { "@/*": ["./src/*"] }
}
}tsconfig.json configures the TypeScript compiler's behavior for the project — Next.js auto-generates a baseline on first run, and it's common to customize it further: enabling "strict" mode for stricter null/type checks, or adding a paths mapping (as above) for cleaner @/component-style imports instead of long relative paths.
Test yourself
A quick mock test covering the ground above — the rapid-fire round that often opens a Next.js interview before the deeper architecture discussion.
Question 1 of 8
Score: 0 / 0
1. What's the App Router's closest equivalent to the Pages Router's getStaticProps?