What is Next.js and why use it
Next.js is a framework built on top of React that handles everything React does not provide out of the box: server-side rendering, routing, optimization and more.
React by itself is a UI library. It does not dictate how to set up routing, where to render pages or how to handle API requests. Next.js answers all of these questions and gives you a ready-made structure for production applications.
What Problem Does Next.js Solve
If you create a React app from scratch using create-react-app or Vite, you get an SPA (Single Page Application). All HTML is generated on the client via JavaScript. This creates several problems:
- SEO. Search engine bots see empty HTML until JavaScript executes. For content sites, blogs and online stores this is critical.
- First load speed. The user waits for all JavaScript to download and execute before seeing any content.
- Infrastructure setup. For SSR, code splitting, image optimization and so on you need to connect and configure a bunch of tools yourself.
Next.js solves all of this out of the box.
Key Features
Multiple Rendering Strategies
Next.js lets you choose a rendering strategy for each page individually:
- SSR (Server-Side Rendering) the page is rendered on the server on every request. Good for dynamic content that changes frequently.
- SSG (Static Site Generation) the page is generated once at build time. Ideal for blogs, documentation, landing pages.
- ISR (Incremental Static Regeneration) a static page that can update in the background at a given interval. A compromise between SSR and SSG.
- CSR (Client-Side Rendering) regular client-side rendering, just like a classic React app.
// SSR: data is fetched on every request
export default async function Page() {
const data = await fetch('https://api.example.com/posts', {
cache: 'no-store'
})
const posts = await data.json()
return <PostList posts={posts} />
}// SSG: data is fetched once at build time (default behavior)
export default async function Page() {
const data = await fetch('https://api.example.com/posts')
const posts = await data.json()
return <PostList posts={posts} />
}// ISR: revalidates every 60 seconds
export default async function Page() {
const data = await fetch('https://api.example.com/posts', {
next: { revalidate: 60 }
})
const posts = await data.json()
return <PostList posts={posts} />
}File-Based Routing
In Next.js you do not need to configure React Router. The file structure inside the app folder automatically becomes your routes:
app/
page.tsx -> /
about/
page.tsx -> /about
blog/
page.tsx -> /blog
[slug]/
page.tsx -> /blog/my-post (dynamic route)Square brackets [slug] create a dynamic segment. Next.js figures out how to match the URL to the component on its own.
Server Components
In the App Router (starting from Next.js 13) components are server components by default. This means they execute on the server and send ready HTML to the client.
// This component runs on the server
// You can directly access the database, file system, etc.
export default async function UsersPage() {
const users = await db.user.findMany()
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}If you need interactivity (useState, onClick, useEffect), add 'use client' at the top of the file:
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Clicks: {count}
</button>
)
}API Routes
Next.js lets you create backend endpoints right inside your project. In the App Router these are called Route Handlers:
// app/api/users/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
const users = await db.user.findMany()
return NextResponse.json(users)
}
export async function POST(request: Request) {
const body = await request.json()
const user = await db.user.create({ data: body })
return NextResponse.json(user, { status: 201 })
}This is handy for simple APIs, form handling, webhooks. For a complex backend it is better to use a separate server.
Built-in Optimization
Next.js includes optimizations that in plain React you would have to set up yourself:
Imagecomponent automatically optimizes images: resizes, converts to WebP, adds lazy loading.Linkcomponent prefetches pages on hover, making navigation instant.Scriptcomponent controls loading of third-party scripts so they do not block rendering.- Automatic code splitting. Each page loads only the JavaScript it needs.
import Image from 'next/image'
import Link from 'next/link'
export default function Header() {
return (
<header>
<Image src="/logo.png" width={120} height={40} alt="Logo" />
<nav>
<Link href="/about">About</Link>
<Link href="/blog">Blog</Link>
</nav>
</header>
)
}How Next.js Differs from React
| React | Next.js | |
|---|---|---|
| Type | Library | Framework |
| Rendering | CSR only | SSR, SSG, ISR, CSR |
| Routing | Needs React Router | Built-in (file-based) |
| SEO | Issues without SSR | Great out of the box |
| API | None | Route Handlers |
| Optimization | Manual | Built-in |
React is not replaced by Next.js. Next.js works on top of React. You still write components, use hooks and everything else from React. Next.js simply adds infrastructure around it.
When to Use Next.js
Good for:
- Content sites and blogs where SEO matters
- Online stores
- Corporate websites
- Dashboards with server-side auth
- Apps where first load speed is important
May be overkill for:
- Small SPAs with no SEO requirements (admin panels, internal tools)
- Apps where all content is generated on the client (for example, graphic editors)
- Prototypes where development speed matters more than optimization
Summary
Next.js is not a replacement for React but a layer on top that turns it from a UI library into a full production framework. It handles server rendering, routing, optimization and API, letting the developer focus on the product instead of configuration.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.