Next.js 15 ships with significant improvements to the App Router — the React Server Component-first routing system introduced in Next.js 13. If you’re still on the Pages Router or are hesitant about the App Router’s complexity, this guide will bring you up to speed on what’s changed and why it matters.
The App Router treats every component as a React Server Component (RSC) by default. RSCs render on the server and ship zero JavaScript to the client. Only components explicitly marked with 'use client' are hydrated in the browser.
// app/page.tsx — Server Component (default)
async function BlogPage() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return (
<ul>
{posts.map(p => <li key={p.id}>{p.title}</li>)}
</ul>
);
}
// components/LikeButton.tsx — Client Component
'use client';
import { useState } from 'react';
export function LikeButton() {
const [liked, setLiked] = useState(false);
return <button onClick={() => setLiked(!liked)}>{liked ? '❤️' : '🤍'}</button>;
}
Parallel routes let you render multiple pages simultaneously in the same layout using @slot conventions. This is ideal for dashboards where a sidebar and main content area load independently.
app/
dashboard/
layout.tsx
@analytics/
page.tsx ← renders independently
@team/
page.tsx ← renders independently
page.tsx
Next.js 15 makes progressive streaming first-class. Wrap slow data-fetching components in <Suspense> and they stream in as they resolve — the shell renders immediately.
import { Suspense } from 'react';
export default function Page() {
return (
<>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<SlowDataComponent />
</Suspense>
</>
);
}
Static and dynamic metadata is now handled through a typed metadata export or a generateMetadata async function — no more custom <Head> components.
// Static
export const metadata = {
title: 'DevForge Blog',
description: 'Expert web development tutorials.',
};
// Dynamic
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return { title: post.title, description: post.excerpt };
}
'use client' when you need interactivity or browser APIs<Suspense> to ship the shell immediately<Head> with the Metadata API for better SEO control