Web Development8 min read
Discover the major improvements in Next.js 16 with Turbopack, async APIs, and PPR for faster web applications.

Next.js 16 is a foundational release that stabilizes Turbopack, introduces Partial Prerendering as stable, and makes significant changes to async request APIs. This guide covers every major feature with practical examples.
Turbopack is now stable and delivers significant performance improvements for both development and production builds.
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
// Turbopack is now the default in Next.js 16!
// No configuration needed
// Optional: Explicitly enable for clarity
turbo: {
rules: {
// Custom loader configurations
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
};
export default nextConfig;Development server with Turbopack:
# Turbopack is now default
npm run dev
# Or explicitly use Turbopack
next dev --turbopackPPR combines static and dynamic rendering in a single route, delivering instant static shell while streaming dynamic content.
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
ppr: 'incremental', // Enable per-route
},
};
export default nextConfig;// app/products/[id]/page.tsx
import { Suspense } from 'react';
import { notFound } from 'next/navigation';
// Enable PPR for this route
export const experimental_ppr = true;
interface ProductPageProps {
params: Promise<{ id: string }>;
}
export default async function ProductPage({ params }: ProductPageProps) {
const { id } = await params;
// Static: Product basic info (prerendered)
const product = await getProduct(id);
if (!product) notFound();
return (
<div>
{/* Static shell - instant load */}
<h1>{product.name}</h1>
<img src={product.image} alt={product.name} />
<p>{product.description}</p>
{/* Dynamic: User-specific recommendations (streamed) */}
<Suspense fallback={<RecommendationsSkeleton />}>
<RecommendationsSection productId={id} />
</Suspense>
{/* Dynamic: Live inventory (streamed) */}
<Suspense fallback={<p>Checking availability...</p>}>
<InventoryStatus productId={id} />
</Suspense>
{/* Dynamic: Reviews (streamed) */}
<Suspense fallback={<ReviewsSkeleton />}>
<ProductReviews productId={id} />
</Suspense>
</div>
);
}
// This component fetches dynamic data
async function RecommendationsSection({ productId }: { productId: string }) {
const recommendations = await getPersonalizedRecommendations(productId);
return (
<div>
<h2>Recommended for you</h2>
{recommendations.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}Next.js 16 makes params, searchParams, cookies, headers, and draftMode async to support modern React patterns.
// ❌ Next.js 15 and earlier
export default function Page({ params, searchParams }) {
const { slug } = params; // synchronous
const { query } = searchParams; // synchronous
return <div>{slug}</div>;
}// ✅ Next.js 16
interface PageProps {
params: Promise<{ slug: string }>;
searchParams: Promise<{ query?: string }>;
}
export default async function Page({ params, searchParams }: PageProps) {
const { slug } = await params;
const { query } = await searchParams;
return <div>{slug} - {query}</div>;
}
// For client components, use React.use()
'use client';
import { use } from 'react';
export function ClientPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = use(params);
return <div>{slug}</div>;
}// app/api/user/route.ts
import { cookies, headers } from 'next/headers';
import { NextResponse } from 'next/server';
export async function GET() {
// ✅ Next.js 16: cookies() is async
const cookieStore = await cookies();
const token = cookieStore.get('auth-token');
// ✅ headers() is also async
const headersList = await headers();
const userAgent = headersList.get('user-agent');
return NextResponse.json({ token, userAgent });
}
// Server Components
export default async function Page() {
const cookieStore = await cookies();
const theme = cookieStore.get('theme')?.value || 'light';
return <div data-theme={theme}>...</div>;
}Next.js 16 changes caching defaults to be more intuitive:
// app/api/products/route.ts
import { NextResponse } from 'next/server';
// ❌ Next.js 15: Cached by default
export async function GET() {
const products = await fetchProducts();
return NextResponse.json(products);
}
// ✅ Next.js 16: Not cached by default
export async function GET() {
const products = await fetchProducts();
return NextResponse.json(products);
}
// To opt into caching in Next.js 16:
export const dynamic = 'force-static';
export const revalidate = 3600; // Revalidate every hour
export async function GET() {
const products = await fetchProducts();
return NextResponse.json(products);
}Next.js provides an automated codemod to handle async API migrations:
# Run the upgrade codemod
npx @next/codemod@canary upgrade latest
# Or specific transforms
npx @next/codemod@canary next-async-request-api .The new after() function lets you execute code after a response is sent, perfect for analytics and cleanup.
import { after } from 'next/server';
import { log } from '@/lib/analytics';
export default async function Page() {
const data = await fetchData();
// Execute after response is sent
after(async () => {
await log('page_view', { timestamp: Date.now() });
await cleanupTempFiles();
});
return <div>{data}</div>;
}Next.js 16 sets a new foundation with stable Turbopack, PPR, and async APIs. While the breaking changes require migration, the performance improvements and developer experience enhancements make the upgrade worthwhile for any serious Next.js application.

Web Development5 min read
Explore the powerful features introduced in React 19.2, including the Compiler, Activity Component, and useEffectEvent, which enhance performance and code quality.

Web Development7 min read
Discover the enhancements in Storybook 10, focusing on performance, testing capabilities, and developer experience.

Web Development5 min read
Explore how Server Actions in Next.js enhance server-side operations for more resilient and user-friendly applications.