Why Next.js Exists
Plain React is a UI library — it renders components in the browser but leaves everything else (routing, data fetching strategy, server-side rendering, image optimization, API routes) up to you. For small projects this flexibility is fine. For production applications, you'd end up building the same infrastructure from scratch on every project. Next.js is React with all of that infrastructure built in, pre-configured, and optimized.
It was created by Vercel (formerly ZEIT) in 2016 and has grown to become the most downloaded React framework. As of 2024, it's used by companies like Netflix, TikTok, Twitch, GitHub, and hundreds of thousands of smaller sites.
What Next.js Adds Over Plain React
| Feature | Plain React | Next.js |
|---|---|---|
| Routing | You add React Router manually | File-based routing built-in |
| Rendering | Client-side only (SPA) | SSR, SSG, ISR, Server Components |
| API routes | Separate Express server needed | Built-in API routes / Route Handlers |
| Image optimization | Manual | Built-in <Image> component |
| SEO | Poor (JS-rendered content) | Excellent (server-rendered HTML) |
| Performance | Manual optimization | Automatic code splitting, prefetching |
Rendering Strategies
The most powerful feature of Next.js is flexible rendering. You can choose how each page is rendered based on its needs.
// Static Site Generation (SSG) — pre-rendered at build time
// Best for: marketing pages, blogs, docs
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map(post => ({ slug: post.slug }));
}
// Server-Side Rendering (SSR) — rendered on each request
// Best for: personalized pages, real-time data
export const dynamic = "force-dynamic";
async function Page({ params }) {
// This runs on the SERVER — never exposed to client
const data = await fetch(`https://api.example.com/data/${params.id}`, {
cache: "no-store" // always fresh data
});
const item = await data.json();
return <div>{item.name}</div>;
}
// Incremental Static Regeneration — regenerate after N seconds
export const revalidate = 60; // regenerate this page every 60 seconds
App Router vs Pages Router
Next.js 13 introduced the App Router, a complete rethink of routing and data fetching using React Server Components. The older Pages Router (files in /pages) still works and is supported, but all new Next.js projects should use the App Router (files in /app). The key difference is that components in the App Router are Server Components by default — they run on the server and can access databases, secrets, and other server-only resources directly, without exposing them to the client.
// app/users/page.tsx — Server Component (default)
// Runs on the server — can query database directly
async function UsersPage() {
const users = await db.user.findMany(); // direct DB access!
return <UserList users={users} />;
}
// "use client" — opt into Client Component when you need interactivity
"use client";
function UserList({ users }) {
const [search, setSearch] = useState("");
// ...interactive filtering
}