
The React 19 Framework
On October 21, 2024, Vercel released Next.js 15—the first major framework built around React 19's new primitives. This release integrates Server Actions, React Compiler, Partial Prerendering, and modernized caching into a cohesive full-stack framework.
Next.js 15 represents the culmination of React's "server-first" vision. With React 19 as its foundation, it treats the server as a first-class rendering environment rather than a deployment target.
Key Changes and New Features
Async Request APIs (Breaking Change)
The most significant breaking change: headers, cookies, params, and searchParams are now asynchronous:
1// Next.js 14 (synchronous)
2import { cookies } from 'next/headers';
3
4export default function Page() {
5 const cookieStore = cookies();
6 const theme = cookieStore.get('theme');
7 return <div>Theme: {theme?.value}</div>;
8}
9
10// Next.js 15 (asynchronous)
11import { cookies } from 'next/headers';
12
13export default async function Page() {
14 const cookieStore = await cookies();
15 const theme = cookieStore.get('theme');
16 return <div>Theme: {theme?.value}</div>;
17}
18
19// Similarly for params:
20// Before: function Page({ params }) { const slug = params.slug; }
21// After: async function Page({ params }) { const { slug } = await params; }This change enables streaming and partial rendering optimizations. A codemod (npx @next/codemod@canary upgrade latest) automates migration.
React Compiler (Experimental)
Next.js 15 integrates the React Compiler—an automatic optimization tool that eliminates the need for manual useMemo, useCallback, and React.memo:
1// Before React Compiler: manual memoization everywhere
2const MemoizedComponent = React.memo(({ items }) => {
3 const sortedItems = useMemo(() =>
4 items.sort((a, b) => a.name.localeCompare(b.name)),
5 [items]
6 );
7 const handleClick = useCallback((id) => {
8 selectItem(id);
9 }, [selectItem]);
10
11 return sortedItems.map(item =>
12 <Item key={item.id} onClick={handleClick} />
13 );
14});
15
16// After React Compiler: just write normal code
17const Component = ({ items }) => {
18 const sortedItems = items.sort((a, b) =>
19 a.name.localeCompare(b.name)
20 );
21 const handleClick = (id) => selectItem(id);
22
23 return sortedItems.map(item =>
24 <Item key={item.id} onClick={handleClick} />
25 );
26};
27// Compiler automatically optimizes re-renders!Enable it in next.config.ts:
1const nextConfig = {
2 experimental: {
3 reactCompiler: true,
4 },
5};Caching Changes (Breaking)
Next.js 15 reverses the aggressive caching defaults that frustrated developers:
| Feature | Next.js 14 | Next.js 15 |
|---|---|---|
| fetch() | Cached by default | Not cached by default |
| GET Route Handlers | Cached by default | Not cached by default |
| Client Router Cache | 5 min stale time | 0 sec (no stale) |
| Page/Layout data | Cached | Not cached |
1// Next.js 14: had to opt out of caching
2fetch(url, { cache: 'no-store' }); // Explicit no-cache
3
4// Next.js 15: fresh data by default, opt in to caching
5fetch(url); // Not cached (fresh every request)
6fetch(url, { next: { revalidate: 3600 } }); // Opt-in to 1-hour cachePartial Prerendering (PPR)
PPR combines static and dynamic rendering in a single page:
1import { Suspense } from 'react';
2
3export const experimental_ppr = true;
4
5export default function ProductPage() {
6 return (
7 <div>
8 {/* Static shell: pre-rendered at build time */}
9 <Header />
10 <ProductImages />
11 <ProductDescription />
12
13 {/* Dynamic parts: streamed on request */}
14 <Suspense fallback={<PriceSkeleton />}>
15 <DynamicPrice /> {/* Real-time pricing */}
16 </Suspense>
17
18 <Suspense fallback={<ReviewsSkeleton />}>
19 <UserReviews /> {/* Personalized reviews */}
20 </Suspense>
21 </div>
22 );
23}The static shell loads instantly (from CDN), while dynamic parts stream in. Users see content immediately with progressive enhancement.
Turbopack Dev (Stable)
After years of development, Turbopack is now stable for development:
| Metric | Webpack | Turbopack | Improvement |
|---|---|---|---|
| Cold start | 8.2s | 1.4s | 5.8x faster |
| HMR (small change) | 450ms | 80ms | 5.6x faster |
| HMR (large change) | 1200ms | 190ms | 6.3x faster |
| Memory usage | 1.8GB | 0.9GB | 50% less |
Enable with next dev --turbopack (or --turbo).
Server Actions Improvements
Server Actions get enhanced security and developer experience:
1'use server';
2
3import { revalidatePath } from 'next/cache';
4import { redirect } from 'next/navigation';
5
6export async function createPost(formData: FormData) {
7 // Server-side validation
8 const title = formData.get('title') as string;
9 const content = formData.get('content') as string;
10
11 if (!title || title.length < 3) {
12 return { error: 'Title must be at least 3 characters' };
13 }
14
15 // Database operation
16 await db.posts.create({ title, content });
17
18 // Revalidate and redirect
19 revalidatePath('/blog');
20 redirect('/blog');
21}Migration Guide
1# Automatic upgrade
2npx @next/codemod@canary upgrade latest
3
4# Key migration steps:
5# 1. Update async request APIs (cookies, headers, params)
6# 2. Review caching behavior (now uncached by default)
7# 3. Test Server Actions
8# 4. Enable Turbopack for dev
9# 5. Optionally enable React CompilerImpact on the Frontend Ecosystem
Next.js 15's integration of React 19 primitives cements the "server-first" paradigm in modern web development. The framework now handles the entire stack—from database queries to interactive UI—with a single, cohesive model.
Sources: Next.js 15 Blog, Next.js Documentation, React 19


