Next.js 15 Complete Guide — App Router, Server Components & What is New in 2026
Advertisement
Introduction
Why This Matters
Next.js 15 is the most capable version of the framework to date. It ships with React Server Components as the default rendering model, Turbopack as the default bundler, and a suite of caching improvements that make applications faster out of the box. For teams building content-heavy sites, SaaS products, or API-driven frontends, understanding these primitives is non-negotiable in 2026.
The shift from Pages Router to App Router fundamentally changes how data flows through your application. Data fetching moves to the server layer, client-side JavaScript shrinks dramatically, and layouts compose without prop drilling. This guide covers every major feature so you can make informed architectural decisions.
The Evolution from Pages Router to App Router
The Pages Router (pages/) works with getServerSideProps, getStaticProps, and file-based routing. It is still supported and will not be removed, but all new Next.js features target the App Router (app/).
Key differences at a glance:
| Feature | Pages Router | App Router |
|---|---|---|
| Default rendering | Client Component | Server Component |
| Data fetching | getServerSideProps | async component + fetch |
| Layouts | _app.tsx | layout.tsx per segment |
| Mutations | API routes | Server Actions |
| Streaming | Not native | Native via Suspense |
The App Router coexists with Pages Router, so migration can happen incrementally.
What is New in Next.js 15
Server Components by Default
Every file in app/ is a React Server Component unless you add 'use client' at the top. Server Components run on the server, have direct access to databases and file systems, and send zero JavaScript to the browser.
// app/page.tsx — runs on the server, no client JS needed
export default async function HomePage() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return (
<main>
{posts.map((post: { id: string; title: string; excerpt: string }) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</main>
)
}Server Actions
Server Actions replace explicit API routes for mutations. They are async functions marked with 'use server', callable directly from forms or event handlers.
// app/actions.ts
'use server'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { db } from '@/lib/db'
export async function createPost(formData: FormData) {
const title = formData.get('title') as string
const content = formData.get('content') as string
const post = await db.posts.create({ data: { title, content } })
revalidatePath('/blog')
redirect(`/blog/${post.id}`)
}// app/create/page.tsx
import { createPost } from '@/app/actions'
export default function CreatePage() {
return (
<form action={createPost} className="space-y-4">
<input name="title" placeholder="Title" className="border p-2 w-full" />
<textarea name="content" placeholder="Content" className="border p-2 w-full" />
<button type="submit" className="bg-blue-600 text-white px-4 py-2 rounded">
Publish
</button>
</form>
)
}Turbopack as Default Bundler
Next.js 15 ships Turbopack as the default dev server bundler. Turbopack is written in Rust and provides 10-100x faster cold starts and HMR compared to Webpack. Most projects require zero config changes to adopt it.
Improved Caching Model
Next.js 15 changed the default caching behavior: fetch requests are no longer cached by default. You must opt in explicitly:
// Opt in to caching for 1 hour
const data = await fetch('/api/data', { next: { revalidate: 3600 } })
// Tag-based revalidation
const posts = await fetch('/api/posts', { next: { tags: ['posts'] } })
// No caching (default in Next.js 15)
const live = await fetch('/api/live')This is a breaking change from Next.js 14 where all fetches were cached by default.
Getting Started
npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app
npm run devThe generated project structure:
my-app/
├── app/
│ ├── layout.tsx # Root layout, wraps every page
│ ├── page.tsx # Home page (/)
│ ├── globals.css
│ └── blog/
│ ├── page.tsx # /blog
│ └── [slug]/
│ └── page.tsx # /blog/:slug
├── components/
├── lib/
├── public/
├── .env.local
└── next.config.tsKey Architecture Concepts
Layouts: layout.tsx files wrap child routes without re-rendering. The root layout in app/layout.tsx must include <html> and <body> tags. Nested layouts compose automatically.
Loading UI: loading.tsx files create instant loading states powered by React Suspense. The UI shows while the page data fetches.
Error Boundaries: error.tsx files catch errors in a route segment without crashing the whole page.
Metadata API: Export a metadata object or generateMetadata function to set SEO tags per route:
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: { title: post.title, images: [post.image] }
}
}Common Mistakes
- Marking components
'use client'unnecessarily — this sends extra JS to the browser and disables async data fetching in that component - Calling
cookies()orheaders()in a Server Component that is statically rendered — these make the route dynamic - Forgetting to
revalidatePathorrevalidateTagafter Server Action mutations, causing stale UI - Not wrapping async Server Components in
<Suspense>— this blocks the full page render until data resolves - Using
process.envvalues without theNEXT_PUBLIC_prefix in Client Components — they will beundefinedat runtime
Best Practices
- Default to Server Components; add
'use client'only at the leaf component that needs interactivity - Keep Server Actions in a separate
app/actions.tsor co-locatedactions.tsfiles, not inline - Use
generateStaticParams+revalidatefor content that changes infrequently (ISR) - Add
priorityprop to the hero image innext/imageto improve LCP - Use
next/fontto self-host Google Fonts and eliminate layout shift from font loading
Key Takeaways
- Next.js 15 uses the App Router by default; all new features target
app/notpages/ - Server Components run only on the server and send zero JavaScript to the browser
- Server Actions replace API routes for mutations and work natively with HTML forms
- Turbopack is the default bundler in Next.js 15, providing significantly faster build times
fetchrequests are NOT cached by default in Next.js 15; you must explicitly opt into caching- Layouts in the App Router nest automatically and do not re-render on child navigation
- The Metadata API (
export const metadata) replaces<Head>from the Pages Router loading.tsxanderror.tsxfiles create Suspense boundaries and error boundaries automatically
Advertisement