Next.js 16 vs 15: Complete Upgrade Guide
Next.js 16 represents one of the most significant updates to the framework, with Turbopack becoming the default bundler and introducing revolutionary caching strategies. This guide covers everything you need to know about upgrading from Next.js 15 to 16.
Quick Start
Upgrade to Next.js 16 using the automated migration tool:
# Automated upgrade with codemods
npx @next/codemod@canary upgrade latest
# Manual upgrade
npm install next@latest react@latest react-dom@latest
# For TypeScript users
npm install @types/react@latest @types/react-dom@latest
Performance Highlights
- 2-5× faster production builds with Turbopack
- Up to 10× faster Fast Refresh in development
- 50% reduction in network transfer for shared layouts
- Instant navigation with Cache Components and PPR
Major Changes Overview
| Feature | Next.js 15 | Next.js 16 |
|---|---|---|
| Default Bundler | Webpack (Turbopack optional) | Turbopack (no config needed) |
| Build Speed | Standard | 2-5× faster |
| Fast Refresh | Standard | Up to 10× faster |
| Caching | Implicit, time-based | Explicit, event-based with "use cache" |
| Middleware File | middleware.ts | proxy.ts |
| Request APIs | Synchronous | Async/Promise-based |
| React Compiler | Experimental | Stable |
| Node.js Minimum | 18.x | 20.9+ |
| React Version | 19.x | 19.2+ |
Turbopack is Now Default
This is the most impactful change. In Next.js 15, Turbopack was optional and required explicit configuration. Now it's your default bundler with no flags needed.
Before (Next.js 15)
{
"scripts": {
"dev": "next dev --turbopack",
"build": "next build --turbopack"
}
}
After (Next.js 16)
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
Turbopack Configuration
The experimental.turbopack configuration is now a top-level option:
import type { NextConfig } from 'next'
// Next.js 15 - experimental.turbopack
const nextConfig: NextConfig = {
experimental: {
turbopack: {
// options
},
},
}
// Next.js 16 - turbopack at top level
const nextConfig: NextConfig = {
turbopack: {
// options
},
}
export default nextConfig
Opting Out of Turbopack
If you need to continue using Webpack:
{
"scripts": {
"dev": "next dev",
"build": "next build --webpack",
"start": "next start"
}
}
Breaking Changes
1. Async Request APIs (Affects ~95% of Apps)
This is the single biggest breaking change. In Next.js 15, params, searchParams, cookies(), headers(), and draftMode() returned values directly. In Next.js 16, they return promises.
Before (Next.js 15)
export default function Page({ params, searchParams }) {
const slug = params.slug
const query = searchParams.q
const cookieStore = cookies()
return <div>{slug} - {query}</div>
}
After (Next.js 16)
export default async function Page({ params, searchParams }) {
const { slug } = await params
const { q } = await searchParams
const cookieStore = await cookies()
return <div>{slug} - {q}</div>
}
Use the codemod to migrate:
npx @next/codemod@canary upgrade latest
2. Node.js 20.9+ Required
Next.js 16 requires Node.js 20.9 or later. Node.js 18 is no longer supported.
# Check your Node version
node --version
3. Middleware Renamed to Proxy
The middleware.ts file is now proxy.ts:
# Rename your middleware file
mv middleware.ts proxy.ts
// Before (Next.js 15)
export function middleware(request: Request) {}
// After (Next.js 16)
export function proxy(request: Request) {}
Configuration flags are also renamed:
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
// Before: skipMiddlewareUrlNormalize
skipProxyUrlNormalize: true,
}
export default nextConfig
4. Image Component Changes
Several defaults have changed:
minimumCacheTTLdefault changed from 60 seconds to 4 hours (14400 seconds)16removed from defaultimageSizesarrayqualitiesdefault changed to only[75]- Local IP optimization blocked by default
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
images: {
// Restore previous behavior if needed
minimumCacheTTL: 60,
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
qualities: [50, 75, 100],
dangerouslyAllowLocalIP: true, // Only for private networks
},
}
export default nextConfig
New Features
Cache Components with "use cache"
Next.js 16 introduces explicit caching with the "use cache" directive:
// next.config.ts
const nextConfig = {
cacheComponents: true,
}
export default nextConfig
'use cache'
async function MyComponent() {
const data = await fetch('/api/users')
return <div>{data}</div>
}
New Caching APIs
'use server'
import { revalidateTag, updateTag } from 'next/cache'
// revalidateTag - for content where slight delay is acceptable
export async function updateArticle(articleId: string) {
revalidateTag(`article-${articleId}`, 'max')
}
// updateTag - for immediate updates (read-your-writes)
export async function updateUserProfile(userId: string, profile: Profile) {
await db.users.update(userId, profile)
updateTag(`user-${userId}`)
}
React 19.2 Integration
Next.js 16 ships with React 19.2, including:
- View Transitions: Animate elements during navigation
- useEffectEvent: Extract non-reactive logic from Effects
- Activity: Render background UI with
display: nonewhile maintaining state
React Compiler (Stable)
The React Compiler is now stable and automatically memoizes components:
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
reactCompiler: true,
}
export default nextConfig
npm install -D babel-plugin-react-compiler
Enhanced Routing and Navigation
- Layout deduplication: Shared layouts downloaded once
- Incremental prefetching: Only prefetch parts not already in cache
Parallel Routes Requirement
All parallel route slots now require explicit default.js files:
// app/@modal/default.tsx
import { notFound } from 'next/navigation'
export default function Default() {
notFound()
}
// Or return null
export default function Default() {
return null
}
Removed Features
- AMP Support: All AMP APIs and configurations removed
- next lint Command: Use ESLint directly
- Runtime Configuration:
serverRuntimeConfigandpublicRuntimeConfigremoved - next/legacy/image: Use
next/imageinstead - images.domains: Use
images.remotePatternsinstead
Migrating Runtime Configuration
Before (Next.js 15)
// next.config.js
module.exports = {
serverRuntimeConfig: {
dbUrl: process.env.DATABASE_URL,
},
publicRuntimeConfig: {
apiUrl: '/api',
},
}
After (Next.js 16)
// For server-only values
async function fetchData() {
const dbUrl = process.env.DATABASE_URL
return await db.query(dbUrl, 'SELECT * FROM users')
}
// For client-accessible values, use NEXT_PUBLIC_ prefix
// .env.local
// NEXT_PUBLIC_API_URL="/api"
'use client'
export default function ClientComponent() {
const apiUrl = process.env.NEXT_PUBLIC_API_URL
return <p>API URL: {apiUrl}</p>
}
Migration Checklist
- ✅ Create a new branch for the upgrade
- ✅ Update Node.js to 20.9+
- ✅ Run the codemod:
npx @next/codemod@canary upgrade latest - ✅ Update all async API usages (params, searchParams, cookies, headers)
- ✅ Rename
middleware.tstoproxy.ts - ✅ Update Turbopack configuration to top-level
- ✅ Add
default.jsfiles to parallel routes - ✅ Review and update image configuration
- ✅ Remove deprecated features (AMP, runtime config)
- ✅ Test thoroughly in staging before production
Conclusion
Next.js 16 brings significant performance improvements and a more explicit approach to caching. While there are breaking changes that require attention, the automated codemods handle most of the migration work. The performance gains from Turbopack alone make the upgrade worthwhile for most projects.
""The best way to predict the future is to create it." - Peter Drucker
Start your migration today and enjoy faster builds, better developer experience, and more control over your application's caching behavior!