Skip to content

What Is Next.js and the App Router

Next.js is a React framework that owns routing, rendering, data fetching, bundling, and optimization for you — and its current model, the App Router, runs your components on the server by default.

Next.js is a React framework, not just a router

Section titled “Next.js is a React framework, not just a router”

Plain React gives you a component model and nothing else — no routing, no server, no build pipeline. Next.js fills that gap. It is the layer that decides how a URL maps to code, where that code runs, and how the result reaches the browser.

Concretely, the framework provides:

  • Routing — folders under app/ become URL segments; there is no route config file to maintain.
  • Rendering — it renders on the server (static or dynamic), streams HTML, and hydrates only what needs interactivity.
  • Data fetching — you can await data directly inside a component, on the server, with no client round-trip.
  • Bundling — it compiles and splits your code with Turbopack, so each route ships only what it needs.
  • Optimizations — images, fonts, scripts, and metadata all have built-in components and APIs.

A route is just a file that default-exports a React component:

app/page.tsx
export default function HomePage() {
return <h1>Hello from a Server Component</h1>;
}

Next.js has two routing systems. The App Router (the app/ directory) is the current, recommended model, built on React Server Components. The Pages Router (the pages/ directory) is the older model; it still works and is fully supported, but it is not where new features land.

The differences are structural, not cosmetic:

app/ pages/
layout.tsx _app.tsx
page.tsx index.tsx
blog/ blog/
page.tsx index.tsx

In the App Router, components are Server Components by default and data fetching happens inline with async/await. In the Pages Router, every component is a Client Component and data comes from special functions like getServerSideProps. This course is App-Router-first; the Pages Router appears only where migrating an existing app matters.

You scaffold a new project with one command:

Terminal window
npx create-next-app@latest my-app

The recommended defaults set you up with TypeScript, ESLint, Tailwind CSS, the App Router, and an AGENTS.md file. The generated tree centers on app/:

my-app/
app/
layout.tsx # root layout (required)
page.tsx # the "/" route
next.config.ts
package.json
tsconfig.json

From here, npm run dev starts the development server and you are looking at a live App Router app.

A request to an App Router route passes through more stages than “run a function, return HTML.” In order: it optionally passes through proxy.ts, Next.js matches it to a route segment, your Server Components render into an RSC payload (with the framework’s cache layers deciding what’s fresh vs. reused), the result streams to the browser as HTML, the browser hydrates the Client Components inside it, and every navigation after that first load fetches more RSC payload instead of a full page. A Server Action call is a POST request that re-enters this same pipeline. Each of those stages is taught in its own lesson elsewhere in this course; The Request Lifecycle walks the whole thing end to end, with the real headers and payloads proved in a running app.

flowchart LR
  Req[Browser request] --> Router[App Router]
  Router --> RSC[Server Components render on server]
  RSC --> HTML[Streamed HTML]
  Router --> Bundle[Minimal client bundle]
  HTML --> Page[Interactive page]
  Bundle --> Page
How a request flows through the App Router

Think of Next.js as everything React deliberately leaves out: it is the layer that decides where your component code runs (server vs. browser), when it runs (build time, request time, or both), and how the result gets to a user. The App Router is not a new templating language bolted onto React — it is Next.js’s current answer to those three questions, built around React Server Components instead of a client-only single-page app.

What you getBenefitCost
App Router (Server Components by default)Data fetching inline with await, minimal client JS, streamingNew mental model if you learned React as client-only
Pages Router (kept for migration)Familiar getServerSideProps/getStaticProps model, huge existing ecosystemEvery component is a Client Component; no new features land here
create-next-app recommended defaultsFastest path to a working, correctly-configured projectCustomizing later means understanding what the defaults chose for you
Framework owning routing/rendering/bundlingYou write far less infrastructure codeYou must learn the framework’s conventions, not just React’s API
  • “Next.js is just a router for React.” Routing is one of five things it owns — it also decides rendering strategy, data fetching ergonomics, bundling, and built-in optimizations for images/fonts/scripts/metadata.
  • “The App Router and Pages Router are two ways to write the same thing.” They are structurally different: App Router components are Server Components by default with inline async/await data fetching; Pages Router components are all Client Components fed by separate functions like getServerSideProps. Code does not port over 1:1.
  • “Every request just runs my page function and returns HTML.” A request passes through proxy, route matching, RSC rendering against multiple cache layers, streaming, and (on later navigations) a client-side RSC fetch — see The Request Lifecycle for the full picture.

When a generated snippet claims to be “a Next.js page,” check for these before trusting it:

  • Does it live under app/ and default-export a component — or does it use Pages-Router-only APIs (getServerSideProps, getStaticProps, a pages/ file) inside what’s supposed to be an App Router project?
  • Does it assume the component is a Client Component (using useState/useEffect with no "use client") when it’s actually a Server Component by default?
  • Does it fetch data through a separate API call from the component, when an async Server Component could await it directly?
  • Is it training-data-era advice that predates the App Router — e.g. treating pages/api as the only way to build an endpoint, when Route Handlers (app/**/route.ts) are the App Router equivalent?

🐛 Spot the bug

app/dashboard/page.tsx
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/stats')
return { props: { stats: await res.json() } }
}
export default function Dashboard({ stats }: { stats: { views: number } }) {
return <p>Views: {stats.views}</p>
}
Show the answer

getServerSideProps is a Pages Router export — it does nothing inside app/. In the App Router, Dashboard is already a Server Component by default, so it can await the fetch directly in its own body instead of exporting a separate data-loading function; stats would be undefined here because Next.js never calls getServerSideProps for App Router routes. The fix is to make Dashboard itself async and await fetch(...) inline, the pattern covered in Server and Client Components.

What does the App Router use as the default type of component?
Which directory signals that a project uses the App Router?
Which of these does Next.js NOT hand to you out of the box?
How does this course treat the Pages Router?
What happens to stats when this file is placed inside app/?
// app/dashboard/page.tsx
export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/stats')
  return { props: { stats: await res.json() } }
}

export default function Dashboard({ stats }: { stats: { views: number } }) {
  return <p>Views: {stats.views}</p>
}
Which statement about these two trees is accurate?
app/                    pages/
  layout.tsx              _app.tsx
  page.tsx                index.tsx