Back/Module F-1 What Is Next.js and Why Does It Exist?
Module F-1·25 min read

The blank canvas problem React creates, the rendering spectrum from CSR to PPR, and what Next.js actually is under the hood — compiler, router, server, and CDN interface.

F-1 — What Is Next.js and Why Does It Exist?

Who this is for: React developers who have built components, managed state, and maybe shipped a Create React App project — but who have never used Next.js and want to understand not just how to use it but why it was built in the first place. If you already know Next.js well, jump to F-3. This module is the foundation everything else builds on.


The Blank Canvas Problem

React gives you something extraordinary: a mental model for building user interfaces out of composable components. It handles rendering, reconciliation, and state beautifully.

What React deliberately does not give you is everything else.

Install React and start from scratch and you are staring at a blank canvas with a set of paintbrushes but no canvas frame, no easel, no way to hang the finished painting. You need to make decisions — dozens of them — before you can ship a single page to a real user:

  • How do users navigate between pages?
  • Where does your HTML come from? Does it get generated in the browser, on a server, or at build time?
  • How do you split your JavaScript so users don't download one enormous bundle?
  • How do you handle environment variables securely?
  • How does your app get deployed?
  • What happens when someone shares a URL to a specific page and opens it for the first time — will the page render instantly or will they see a blank screen for two seconds while JavaScript boots?

These are not academic questions. Every production React application answers all of them. The question is whether you answer them yourself by assembling a bespoke toolchain, or whether you use a framework that has already made those decisions — well — on your behalf.

Next.js is the answer to that second question.


What Next.js Actually Is

It helps to think of Next.js as four things wearing a single coat:

1. A file-system router. You create files in an app/ directory and Next.js turns them into URL routes automatically. app/blog/[slug]/page.tsx becomes /blog/anything-you-want. No router configuration files, no <Route> components, no path string maintenance.

2. A compiler. Next.js ships with SWC (a Rust-based TypeScript/JavaScript compiler) and Turbopack (a Rust-based bundler built to replace Webpack). You write TypeScript and React — Next.js handles transpilation, minification, tree shaking, and code splitting without you writing a single line of build configuration.

3. A server with multiple rendering modes. Next.js can render your React components on a server, at build time, or in the browser — or any combination of the three within the same application. It decides how to render each page based on rules you control, and it handles the mechanics of sending HTML, streaming it in chunks, and hydrating the result in the browser.

4. A CDN integration layer. Next.js has a deep, first-class integration with the concept of edge networks and content delivery. It knows how to generate cache headers, tell a CDN when content is stale, revalidate pages in the background without taking them offline, and execute code at the network edge close to users rather than in a central data center.

You can use Next.js without Vercel (the company that builds it — more on that shortly). But understanding this CDN integration layer is crucial to understanding why Next.js makes the decisions it makes.


The Rendering Spectrum

The most important concept in all of Next.js is not a hook, an API, or a configuration option. It is a mental model: the rendering spectrum.

Every web page you have ever visited sits somewhere on this spectrum. Understanding where different types of content belong — and what the trade-offs are at each point — is the skill that separates developers who use Next.js from developers who truly understand it.

Point 1: Client-Side Rendering (CSR)

The original React model. Your server sends a nearly empty HTML file with a <script> tag. The browser downloads JavaScript, executes it, your React application boots, it fetches data from an API, and eventually renders something meaningful.

Browser request → Empty HTML → JS downloads → JS executes → API call → Render

Where this works well: Highly interactive applications where the user is always logged in, where SEO doesn't matter (internal dashboards, admin panels, tools behind authentication), and where the content is always different per user so pre-rendering provides no benefit.

Where this breaks: Any page where someone might arrive via a search engine, share a link, or encounter it for the first time. The page is invisible to web crawlers unless they execute JavaScript (many don't). Users on slow connections see nothing for 2–4 seconds. Your Largest Contentful Paint score — the core metric Google uses for search ranking — is catastrophic.

Point 2: Server-Side Rendering (SSR)

When a user requests a page, your server runs the React components, fetches the data they need, generates complete HTML, and sends it. The browser receives a fully rendered page immediately.

Browser request → Server fetches data → Server renders HTML → Full page arrives

Where this works well: Content that changes frequently and is different for each user — an authenticated feed, a personalised homepage, real-time inventory counts.

Where this breaks: It doesn't scale gracefully under load. Every page view requires your server to do work. If ten thousand people hit your homepage simultaneously, your server is rendering that page ten thousand times even if the content is identical for all of them.

Point 3: Static Site Generation (SSG)

Your pages are rendered once at build time. The resulting HTML files are stored and served directly from a CDN. No server work happens per request — you're just serving files.

Build time → Server renders HTML once → Files stored on CDN → Requests served instantly

Where this works well: Content that doesn't change often — marketing pages, blog posts, documentation, product landing pages. A CDN can serve a static HTML file to millions of users simultaneously with near-zero latency.

Where this breaks: If you have 500,000 product pages, rebuilding every one of them on every deploy becomes a 40-minute build. And if a product's price changes, users see stale data until the next build.

Point 4: Incremental Static Regeneration (ISR)

The hybrid solution. Pages start as statically generated files. After a configurable time window (say, 60 seconds), the next request triggers a background regeneration. The user still gets the cached version immediately, but behind the scenes Next.js re-renders the page and stores a fresh copy for future requests.

First request → Cached HTML (instant) → Background: re-render if stale → Next request: fresh HTML

Where this works well: Large catalogs where you need near-real-time accuracy but can't afford full SSR costs. E-commerce product pages, news articles, sports scores — content that changes but can tolerate being a few seconds (or minutes) stale.

Point 5: Partial Prerendering (PPR)

The newest point on the spectrum, introduced in Next.js 14 and stabilising in Next.js 15. A single page has a static shell — the nav, the layout, the surrounding structure — served instantly from a CDN, and dynamic holes — the personalised content, the live inventory count, the user-specific data — streamed in from the server immediately after.

Request → Static shell from CDN (instant) → Dynamic slots stream in (milliseconds later)

Where this works well: E-commerce product pages where the product description, images, and reviews are static, but the price, stock status, and "Add to Cart" button are dynamic and personalised.

This is not a course on rendering theory — but every decision you make in Next.js traces back to this spectrum. When you're deciding whether to put 'use client' on a component, or whether to add cache: 'no-store' to a fetch call, or whether to wrap something in <Suspense> — you are making a rendering spectrum decision.


App Router vs Pages Router: The Definitive Answer

If you have looked at any Next.js tutorials or job postings in the past two years, you have probably encountered the "App Router vs Pages Router" question. Here is the answer you need before starting this course:

This course covers the App Router exclusively. The Pages Router is legacy infrastructure.

That is not a dismissive statement — the Pages Router powers millions of production applications and will continue to receive security patches and bug fixes for years. If you are working on an existing Pages Router codebase, understanding it is important. But for new development, the question has been settled.

Here is why the App Router exists and why it matters:

The Pages Router was built for a world where SSR meant "run a function on the server before rendering." This worked well for simple cases, but it had a fundamental limitation: data fetching was colocated at the page level, not the component level. If your <ProductDetail> component needed product data and your <RelatedProducts> component needed separate recommendations data, both had to be fetched in a single getServerSideProps function at the top of the page. Every intermediate component had to receive everything as props. The components themselves were stateless recipients.

React Server Components — the foundation of the App Router — inverted this model. Components themselves can now be async and fetch their own data directly. A <ProductDetail> component can query the database. A <RelatedProducts> component can call a recommendations API. They do this on the server, in parallel, with no props drilling and no shared state required.

This is not just a developer experience improvement. It changes the entire architecture of how data flows through your application. It is why modules F-3 through F-5 of this course spend substantial time on the Server Component mental model before touching anything else.


The Vercel Relationship

Vercel is the company that created and primarily develops Next.js. The framework is open source (MIT license) and has hundreds of contributors outside Vercel. You can run Next.js on any platform that supports Node.js.

But it is worth being honest about the relationship: some Next.js features — particularly around edge computing, ISR, and certain caching primitives — work best (or, in some cases, exclusively) when deployed to Vercel's infrastructure. The framework is not secretly a vendor lock-in tool, but the deeper you go into the Architect phase of this course, the more you will encounter features where self-hosting requires additional work that Vercel handles automatically.

This course will always tell you when something is Vercel-specific and what the self-hosting equivalent looks like. Module A-14 is dedicated entirely to the deployment matrix and long-lived connections.

For now: you can build and run everything in this course locally, deploy to Vercel for free on their hobby tier, or deploy to any other host. The concepts transfer everywhere.


Installing Next.js

You need Node.js 18.17 or later. If you're not sure which version you have:

bash
node --version

Create a new Next.js application:

bash
npx create-next-app@latest my-app

The CLI will ask you several questions. Here is what to answer for this course:

QuestionAnswer
TypeScript?Yes — TypeScript is the standard for production Next.js work
ESLint?Yes — catches common mistakes automatically
Tailwind CSS?Yes — we'll use Tailwind throughout the course
src/ directory?Yes — keeps source code separate from config files at the root
App Router?Yes — this is what we're learning
Turbopack for development?Yes — faster dev server
Import alias?Yes, @/* — cleaner imports throughout the course

Project Structure Walkthrough

After create-next-app completes, your project looks like this:

my-app/
├── src/
│   └── app/
│       ├── favicon.ico
│       ├── globals.css
│       ├── layout.tsx        ← Root layout — wraps every page
│       └── page.tsx          ← The homepage ( / )
├── public/                   ← Static files (images, fonts, etc.)
├── next.config.ts            ← Next.js configuration
├── tailwind.config.ts        ← Tailwind CSS configuration
├── tsconfig.json             ← TypeScript configuration
└── package.json

Open src/app/page.tsx. This is the most important file in the project:

tsx
export default function Home() { return ( <main> <h1>Hello, world</h1> </main> ); }

This is a React Server Component. It runs on the server. It can be async. It can fetch data directly. It never runs in the browser.

That last sentence — it never runs in the browser — is the mental model shift that the entire App Router is built on. We will spend all of F-3 unpacking exactly what that means and why it changes how you structure applications.

Open src/app/layout.tsx:

tsx
import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; import './globals.css'; const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { title: 'My App', description: 'Built with Next.js', }; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}>{children}</body> </html> ); }

This layout wraps every page in your application. The metadata export handles your <title> and <meta> tags automatically — no next/head, no manual <title> tags. The children prop is where each page gets inserted.


The Four npm Scripts

json
{ "scripts": { "dev": "next dev --turbopack", "build": "next build", "start": "next start", "lint": "next lint" } }
  • npm run dev — starts the development server on http://localhost:3000 with hot module replacement. The --turbopack flag uses the new Rust bundler for significantly faster startup and rebuild times.
  • npm run build — compiles your application for production. This is where Next.js decides which pages to statically generate and which to render dynamically. Read the build output carefully — it tells you exactly what each route will do in production.
  • npm run start — starts a production server from the compiled output. Run build first.
  • npm run lint — runs ESLint with Next.js-specific rules that catch common mistakes (missing alt tags on images, incorrect usage of <Link>, etc.).

Reading the Build Output

After running npm run build, Next.js prints a summary that looks like this:

Route (app)                              Size     First Load JS
┌ ○ /                                    5.2 kB         92.3 kB
├ ○ /about                               1.1 kB         88.2 kB
├ ● /blog/[slug]                         2.8 kB         89.9 kB
└ ○ /contact                             1.4 kB         88.5 kB

○  (Static)   prerendered as static content
●  (SSG)      prerendered as static HTML (uses generateStaticParams)
λ  (Dynamic)  server-rendered on demand

Learn to read this output. It tells you — before you deploy a single byte — exactly which rendering strategy each route is using. A λ on a page that should be means you accidentally made it dynamic somewhere. An on a page that should be λ means you might be serving stale content. This output will become one of your most-used diagnostic tools.


What Next.js Is Not

Before we go further, it is worth setting three expectations clearly.

Next.js is not a backend framework. It can handle API routes and server-side logic, but it is not Express, Fastify, or NestJS. If you need a dedicated API layer with complex business logic, background job processing, or a sophisticated database access layer, Next.js route handlers are often not the right tool — or they coexist alongside a dedicated backend service.

Next.js is not opinionated about your database. It has no built-in ORM, no preferred database, and no migration system. You bring those yourself (Prisma, Drizzle, raw SQL — your choice). This is a feature, not a gap.

Next.js is not magic. The framework makes a lot of things automatic — routing, code splitting, image optimisation, font loading — but every one of those automations has mechanics you can understand and, when needed, override. This course is fundamentally about understanding those mechanics so you can work with them deliberately rather than accidentally.


Where We Go From Here

This module established the why of Next.js. The remaining Foundation modules build the mental model and practical skills you need to ship real applications.

The single most important thing to carry forward: Next.js is a spectrum, not a switch. Every feature — caching, rendering modes, data fetching strategies, edge compute — lives somewhere on a continuum between "runs once at build time, served forever" and "runs on every request, always fresh." Your job as a Next.js developer is not to learn which button to press for each scenario. It is to build the judgment to know where on that spectrum each piece of your application belongs.

That judgment is what the next 36 modules build.

Discussion