The most common question from JavaScript beginners: "Should I learn React or Next.js?" The answer is simpler than most tutorials make it seem. React is a UI library. Next.js is a framework built on top of React. You need to know React to use Next.js, and knowing React alone is enough for many projects.
At a glance
| React | Next.js | |
|---|---|---|
| Type | UI library | Full-stack framework |
| Created by | Meta (2013) | Vercel (2016) |
| Rendering | Client-side only (by default) | SSR, SSG, ISR, RSC, CSR — your choice |
| Routing | External library (React Router, TanStack) | Built-in file-system router |
| Backend | None | API Routes / Server Actions |
| SEO | Poor out of the box | Excellent |
| Setup | Vite / CRA | npx create-next-app |
| Learning order | Learn this first | Learn after React basics |
| Bundle size | Ships React runtime | Also ships React + Next.js runtime |
| Deploy target | Any static host | Optimised for Vercel, works anywhere |
What React actually is
React is a JavaScript library for building user interfaces. That's it. It gives you:
- A component model (split UI into reusable pieces)
- JSX syntax (HTML-like tags in JavaScript)
- State management (
useState,useReducer) - Side-effect handling (
useEffect) - Context for global data (
useContext)
What React does not give you:
- Routing (you add React Router or TanStack Router)
- Data fetching conventions (you add TanStack Query or SWR)
- Server-side rendering
- API endpoints
- A build system (you add Vite)
- SEO helpers
A plain React app renders everything in the browser. The server sends one empty <div id="root"></div> and a JavaScript bundle. The browser runs the JS, which builds the entire page. This is called a Single-Page Application (SPA).
// Plain React — this all runs in the browser
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
}
What Next.js actually is
Next.js is a React framework that adds everything React lacks for production web apps:
- File-system routing —
app/about/page.tsxbecomes/about - Multiple rendering strategies — choose per page
- Server Components — React components that run on the server
- Server Actions — write backend logic right inside your component files
- API Routes — build REST/JSON endpoints in the same project
- Image optimisation —
<Image>auto-resizes and converts to WebP - Font optimisation — fonts load with zero layout shift
- Metadata API —
<title>, Open Graph, Twitter cards from config
// Next.js Server Component — runs on the server, no JS sent to browser
async function ProductPage({ params }: { params: { id: string } }) {
// This fetch runs on the server at request time
const product = await fetch(`https://api.example.com/products/${params.id}`)
.then(r => r.json())
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
</div>
)
}
Rendering strategies explained
This is the biggest difference in practice.
| Strategy | Where HTML is built | When | Best for |
|---|---|---|---|
| CSR (React default) | Browser | On every visit | Dashboards, apps behind login |
| SSR | Server | On every request | Product pages, news, user-specific content |
| SSG | Build time | Once, pre-built | Blogs, docs, marketing pages |
| ISR | Server + cache | First hit, then cached N seconds | Frequently-updated static content |
| RSC | Server | On every request | Any page — replaces SSR for most cases |
| PPR (Partial Prerendering) | Mixed | Build + request | Pages with static shell + dynamic content |
With plain React (SPA), you only get CSR. Next.js gives you all of the above.
Why rendering strategy matters
SEO: Google can crawl server-rendered HTML immediately. A CSR app sends an empty <div> — Googlebot has to execute JS to see the content, which is slower and less reliable.
Performance: SSG pages are served from a CDN edge in milliseconds. CSR pages make the user download JS, parse it, fetch data, and then render — slower on mobile.
Time to First Byte (TTFB): SSR sends complete HTML on the first network response. CSR needs multiple round-trips before the user sees content.
File routing comparison
React (with React Router)
// router/index.jsx — manual route definitions
import { createBrowserRouter } from 'react-router-dom'
import Home from '../pages/Home'
import About from '../pages/About'
import Product from '../pages/Product'
export const router = createBrowserRouter([
{ path: '/', element: <Home /> },
{ path: '/about', element: <About /> },
{ path: '/products/:id', element: <Product /> },
])
Next.js (App Router)
app/
page.tsx → /
about/
page.tsx → /about
products/
[id]/
page.tsx → /products/:id
loading.tsx → loading UI while data fetches
error.tsx → error boundary
not-found.tsx → 404 for this segment
No router configuration file. The folder structure is the router.
Data fetching comparison
React SPA approach
import { useEffect, useState } from 'react'
function Products() {
const [products, setProducts] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
fetch('/api/products')
.then(r => r.json())
.then(data => {
setProducts(data)
setLoading(false)
})
}, [])
if (loading) return <p>Loading...</p>
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}
Issues: data not available during SSR, waterfall requests, no caching.
Next.js Server Component approach
// No useEffect, no useState, no loading state — just async/await
async function Products() {
const products = await fetch('https://api.example.com/products', {
next: { revalidate: 60 } // cache for 60s, then refresh
}).then(r => r.json())
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}
The HTML arrives with data already embedded. Zero client-side JavaScript for this component.
Server Actions — backend without an API file
Next.js allows you to write server-side code directly inside your component:
// No separate API route needed
async function ContactPage() {
async function sendEmail(formData: FormData) {
'use server' // this function runs on the server
const email = formData.get('email')
const message = formData.get('message')
await db.messages.create({ data: { email, message } })
// revalidatePath('/contact')
}
return (
<form action={sendEmail}>
<input name="email" type="email" required />
<textarea name="message" required />
<button type="submit">Send</button>
</form>
)
}
In React alone you'd need a separate Express/Fastify server with its own routes, CORS config, and API client code.
When to use React (without Next.js)
| Use case | Why React alone works |
|---|---|
| Dashboard / admin panel | Behind auth, SEO doesn't matter |
| Internal tools | No public indexing needed |
| Desktop app (Electron/Tauri) | No server-side rendering possible |
| Mobile app (React Native) | Next.js doesn't run on native |
| SaaS app (fully behind login) | CSR is fine, SSR adds complexity |
| Prototype / MVP | Fewer moving parts |
| Learning React | Understand the foundation first |
| Static site with no routing complexity | Vite + React is simpler |
When to use Next.js
| Use case | Why Next.js helps |
|---|---|
| Marketing / landing pages | SSG → fast load, perfect SEO |
| Blog / content site | SSG/ISR for fast, crawlable pages |
| E-commerce | SSR product pages, SEO, image optimisation |
| News / media site | ISR keeps content fresh without full deploys |
| SaaS with a public-facing landing page | Mix of SSG (landing) + CSR (dashboard) |
| Full-stack in one repo | API routes + Server Actions replace Express |
| When SEO matters | Server-rendered HTML for crawlers |
| Startup MVP with a tight deadline | Auth + DB + frontend in one framework |
Ecosystem: what Next.js adds
| Feature | React (need to install) | Next.js (built in) |
|---|---|---|
| Routing | React Router / TanStack Router | File-system router |
| SSR/SSG | react-helmet + express | Native |
| Image optimisation | manual | next/image |
| Font loading | manual | next/font |
| Meta tags / SEO | react-helmet | Metadata API |
| API endpoints | Separate Express server | /app/api/route.ts |
| Code splitting | Manual or bundler config | Automatic per route |
| Environment variables | .env + vite config |
.env.local + built-in |
| TypeScript config | Manual tsconfig | Pre-configured |
| Middleware | Not applicable | middleware.ts runs on edge |
Performance comparison
| Metric | React SPA | Next.js (SSG) | Next.js (SSR) |
|---|---|---|---|
| First Contentful Paint | Slow (needs JS) | Very fast (CDN HTML) | Fast (server HTML) |
| SEO crawlability | Poor | Excellent | Excellent |
| Server cost | Zero (static files) | Near zero (CDN) | Node.js server needed |
| Build time | Fast | Slow for 10k+ pages | Fast |
| Time to Interactive | Slow (big JS bundle) | Fast | Fast |
| Cache-ability | Easy (one bundle) | Easy (per-page CDN) | Complex (per-request) |
| Complexity | Low | Medium | Medium–High |
Learning order: always React first
1. JavaScript fundamentals
↓
2. React basics
- JSX, components, props
- useState, useEffect
- Lifting state up
- Conditional rendering
- Lists and keys
- Basic forms
↓
3. React ecosystem
- React Router (client-side routing)
- TanStack Query or SWR (data fetching)
- Zustand or Jotai (global state)
↓
4. Next.js
- App Router, layouts, pages
- Server Components vs Client Components
- Data fetching (fetch, revalidate)
- Server Actions
- Metadata API, next/image
Don't skip step 2. Next.js hides a lot of React, so if you jump straight to it you'll hit walls when you need to debug or customise behaviour.
Common confusion points
"Is Next.js replacing React?"
No. Next.js runs React. Every React skill transfers. Next.js is React with more features on top. React is maintained by Meta; Next.js is maintained by Vercel.
"Can I use React components in Next.js?"
Yes, completely. Every component you wrote for a React SPA works in Next.js. The only difference is that some features (hooks, event handlers) can only run in Client Components, marked with 'use client'.
"Do I need a Node.js server to run Next.js?"
Not necessarily. Next.js has multiple output modes:
| Mode | Server needed? |
|---|---|
next export (static) |
No — serves from any CDN |
| SSG with no dynamic routes | No |
| SSR / Server Components | Yes (Node.js, Deno, or edge) |
| Vercel / similar platforms | Managed for you |
"Is Vite replacing Create React App?"
Yes. Create React App is unmaintained. Use Vite for plain React SPAs. Next.js has its own bundler (Turbopack) so you don't configure Vite with Next.js.
Full comparison table
| Feature | React (Vite) | Next.js |
|---|---|---|
| Type | UI library | Full-stack framework |
| Routing | Manual (React Router) | File-system built-in |
| Rendering | CSR only | CSR, SSR, SSG, ISR, RSC, PPR |
| API backend | Separate server | Built-in API routes |
| SEO | Poor by default | Excellent |
| Image optimisation | None | next/image |
| Font optimisation | None | next/font |
| TypeScript | Manual config | Pre-configured |
| Learning curve | Lower | Higher (more concepts) |
| Bundle size | ~45 KB React runtime | ~45 KB React + Next.js runtime |
| Deployment | Any static host | Vercel-optimised, others work |
| Full-stack | No | Yes |
| Middleware | No | Edge middleware |
| Auth | Manual | NextAuth.js integrates natively |
| Caching | Browser only | Browser + server + CDN |
| Built-in DB access | No | Server Actions reach DB directly |
| Code splitting | Manual | Automatic per route |
| Community size | Massive | Large and growing |
| Job listings | Very high | High and growing |
| When to choose | SPAs, apps behind login, mobile, desktop | Public sites, content, SEO, full-stack |
Decision guide
Does your app need SEO?
├── YES → Use Next.js (SSG or SSR)
│
└── NO → Is it behind a login / internal tool?
├── YES → React SPA is fine
│
└── NO → Does it need a backend?
├── YES → Next.js (Server Actions + API routes)
│
└── NO → React SPA with Vite
Are you just learning?
└── Start with React. Add Next.js once you're comfortable with hooks and components.
Building a marketing site or blog?
└── Next.js with SSG. Deploy to Vercel or Netlify for free.
Building a SaaS?
└── Next.js: SSG for landing page, CSR for dashboard. One repo, one deploy.
Common mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Learning Next.js before React | Confused by RSC, 'use client', hooks | Spend 2–4 weeks on plain React first |
Using useEffect for data in Next.js |
Defeats SSR, causes flicker | Use async Server Components + fetch |
Wrapping everything in 'use client' |
Loses all SSR benefits | Only mark components that use hooks or browser APIs |
| Fetching in Client Component when data is static | Slow, SEO-poor | Move data fetch to parent Server Component |
| Putting secrets in client-side code | Security risk | Use environment variables prefixed without NEXT_PUBLIC_ |
Skipping next/image for images |
Large images slow page | Replace <img> with <Image> |
| Ignoring build output warnings | Missing optimisation | Always fix warnings before shipping |
| Using pages router in new projects | Legacy pattern | Use App Router (stable since Next.js 13.4) |
FAQ
Q: Which pays more — React or Next.js?
Both use the same job title ("React Developer" or "Frontend Developer"). Knowing Next.js makes you more hireable for full-stack and senior roles. Salary difference is negligible — it's the experience level that drives pay.
Q: Can I use Next.js without a Vercel account?
Yes. Next.js runs on any Node.js server, Docker, AWS Lambda, Cloudflare Workers, or as a purely static export. Vercel just has the best integration since they built Next.js.
Q: Is the App Router stable?
Yes. The App Router (file-based, Server Components, Server Actions) has been stable since Next.js 13.4 (released May 2023). Use it for all new projects. The Pages Router still works but is in maintenance mode.
Q: Do I need TypeScript with Next.js?
No, but highly recommended. Next.js has first-class TypeScript support with zero configuration. Most Next.js tutorials and the official docs use TypeScript.
Q: Can I use Zustand / Redux with Next.js?
Yes. Zustand, Jotai, Redux Toolkit all work with Next.js. They run in Client Components ('use client'). For server-side data, use fetch + React cache instead of client-side stores.
Q: Is Next.js good for a REST API backend?
For small projects and microservices, yes. Route Handlers (/app/api/route.ts) let you build REST APIs in Next.js. For a dedicated high-performance API, use FastAPI (Python) or Fastify (Node.js) separately. Next.js is not a replacement for a purpose-built API server at scale.