Next.js 15: Full Feature Breakdown, Breaking Changes & Upgrade Guide

July 17, 2024 Β· 6 min read

Next.js 15 was released on October 21, 2024, at Next.js Conf 2024. It ships the most significant behavioral change in the framework's history: caching is now uncached by default. This guide covers every feature that shipped in stable form, async Request APIs, the new <Form> component, stable Turbopack development mode, instrumentation.js, Server Actions security, next.config.ts TypeScript support, and all breaking changes to handle before upgrading.
The biggest breaking change: Async Request APIs
The most impactful change in Next.js 15 is that all request-scoped APIs are now async. In Next.js 14, you could call cookies(), headers(), draftMode(), params, and searchParams synchronously. In Next.js 15, every one of these must be awaited.
The reason for this change: it enables Next.js to prepare work before a request arrives, which opens the door to more aggressive prerendering and caching optimizations in future versions.
// Next.js 14 β synchronous (no longer works)
import { cookies } from 'next/headers'
export default function Page() {
const cookieStore = cookies()
const token = cookieStore.get('token')
return <div>{token?.value}</div>
}// Next.js 15 β async required
import { cookies } from 'next/headers'
export default async function Page() {
const cookieStore = await cookies()
const token = cookieStore.get('token')
return <div>{token?.value}</div>
}The same pattern applies to headers(), draftMode(), and the params/searchParams props in layouts and pages:
// Next.js 15 β params and searchParams are now async
export default async function ProductPage({
params,
searchParams,
}: {
params: Promise<{ id: string }>
searchParams: Promise<{ sort: string }>
}) {
const { id } = await params
const { sort } = await searchParams
return <div>Product {id} sorted by {sort}</div>
}Run the automated codemod to migrate all call sites at once:
npx @next/codemod@canary next-async-request-api .Caching is now uncached by default
This is the change most likely to break existing Next.js 14 applications silently. In Next.js 14, fetch requests were cached by default. In Next.js 15, they are not, every fetch call is treated as dynamic unless you explicitly opt in to caching.
Three things are now uncached by default:
fetchrequests (previously cached unless you addedcache: "no-store")GET Route Handlers (previously cached by default)
Client Router Cache page segments (
staleTimeis now 0 β page data is always re-fetched on navigation)
To opt back in to caching where you need it:
// Cache a single fetch call
const data = await fetch('/api/products', { cache: 'force-cache' })
// Cache an entire route segment
export const dynamic = 'force-static'
// Cache all fetches in a layout or page
export const fetchCache = 'default-cache'React 19 support
Next.js 15 ships with React 19 support for the App Router. The Pages Router retains React 18 backward compatibility, you can upgrade Next.js to 15 without upgrading React if your app uses the Pages Router.
App Router: React 19 stable (includes
useActionState,useOptimistic, Server Actions, and more)Pages Router: React 18 remains compatible - upgrade independently
React Compiler: available as experimental (
reactCompiler: trueinnext.config.ts)Hydration error messages now show a source code diff of what the server rendered vs. what the client expected
Turbopack Dev is now stable
next dev --turbo is stable in Next.js 15. The performance gains compared to the webpack-based dev server are substantial:
76.7% faster local server startup
96.3% faster Fast Refresh (measured on vercel.com)
45.8% faster initial route compile
Note: Turbopack in Next.js 15 is stable for development only. Production Turbopack builds (next build --turbo) are stable in Next.js 16.
The new <Form> component
Next.js 15 introduces next/form, a form component that extends the native HTML <form> with three automatic behaviors:
Prefetches the destination layout and loading UI when the form enters the viewport
Client-side navigation on submit (preserves shared layouts, no full page reload)
Progressive enhancement (works without JavaScript)
import Form from 'next/form'
export default function SearchForm() {
return (
<Form action="/search">
<input name="q" placeholder="Search..." />
<button type="submit">Search</button>
</Form>
)
}On submission, the query string is appended to the action URL and the user navigates client-side to /search?q=... without a full page reload.
unstable_after() for post-response work
unstable_after() lets you execute code after a response has finished streaming, without blocking the response. This is the right place for analytics tracking, audit logging, and external system syncs that should not add latency for the user.
Enable it in next.config.ts first:
const nextConfig = {
experimental: {
after: true,
},
}
export default nextConfigimport { unstable_after as after } from 'next/server'
import { recordPageView } from '@/lib/analytics'
export default async function Page() {
after(() => {
// Runs after the response streams β does not block the user
recordPageView()
})
return <div>Page content</div>
}instrumentation.js is now stable
instrumentation.js (or instrumentation.ts) is a special file at the root of your project that Next.js calls once when the server starts. Use it to initialize observability providers (OpenTelemetry, Sentry, Datadog) and set up error tracking.
Next.js 15 adds the onRequestError hook, which fires for every server error with full request context, route, component type, and the error itself:
// instrumentation.ts
export function register() {
// Initialize your observability provider once on server start
Sentry.init({ dsn: process.env.SENTRY_DSN })
}
export function onRequestError(
error: Error,
request: { path: string; method: string },
context: { routeType: string }
) {
Sentry.captureException(error, {
extra: { path: request.path, routeType: context.routeType },
})
}Server Actions security improvements
Next.js 15 ships two Server Actions security improvements that happen automatically with no configuration required:
Dead code elimination: Server Actions that are defined but never imported or called from a Client Component are removed from the client bundle entirely. Previously they could be exposed as callable endpoints even if unused.
Unguessable action IDs: Action IDs are now non-deterministic and rotated between builds. A URL observed in one build cannot be used to call a Server Action in a subsequent build.
next.config.ts TypeScript support
Next.js 15 supports next.config.ts natively. Rename your config file and use the NextConfig type for full autocomplete and type checking on every config option:
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
// Full autocomplete and type safety here
}
export default nextConfigStatic Route Indicator
Next.js 15 adds a visual indicator in development mode that shows whether the current route is rendered statically or dynamically. This makes it easy to verify that a route you expect to be static has not accidentally become dynamic (for example, due to an uncached fetch call or a cookies() read). To disable it in config:
const nextConfig: NextConfig = {
devIndicators: {
appIsrStatus: false,
},
}Breaking changes summary
Change | What to do |
|---|---|
Node.js 18.18.0 minimum | Upgrade Node.js if below 18.18.0 |
| Await all calls; run |
| Await in layouts and pages; type as |
| Install |
| Use |
| Audit all fetch calls; add |
| Move dynamic import to a Client Component |
Should you upgrade to Next.js 15 or go straight to 16?
If you are currently on Next.js 14 and starting an upgrade today, go straight to Next.js 16. The migration effort is similar and you get additional improvements: stable Turbopack production builds, Cache Components with the "use cache" directive, proxy.ts, and React 19.2.
If you are already on Next.js 15, the upgrade to 16 is worthwhile and the codemod handles most of the breaking changes. The key things to address manually: revalidateTag() now requires a second argument, and middleware.ts should be renamed to proxy.ts.
How to upgrade to Next.js 15
Run the automated codemod first, it handles async Request API migrations and most other breaking changes:
npx @next/codemod@canary upgrade latestTo upgrade manually:
npm install next@15 react@19 react-dom@19Bring Your Ideas to Life π
If you need help with a Next.js project let's get in touch.
Lucky Media is proud to be recognized as a leading Next.js Development Agency
FAQs
Is Next.js 15 stable?
Yes. Next.js 15 was released on October 21, 2024, at Next.js Conf 2024. It is stable and production-ready.
What is the biggest breaking change in Next.js 15?
The async Request APIs. In Next.js 15, cookies(), headers(), draftMode(), params, and searchParams are all async and must be awaited. Run the automated codemod (npx @next/codemod@canary next-async-request-api .) to migrate most of your codebase automatically.
Do I need React 19 to use Next.js 15?
No. The Pages Router in Next.js 15 is backward compatible with React 18. The App Router uses React 19. You can upgrade Next.js to 15 without changing your React version if you use the Pages Router.
Is Turbopack stable in Next.js 15?
Turbopack is stable for development (next dev --turbo) in Next.js 15. Production Turbopack builds (next build --turbo) became stable in Next.js 16.
Should I upgrade to Next.js 15 or go straight to Next.js 16?
If you are on Next.js 14 today, go straight to Next.js 16. The migration effort is similar to going to 15, and you get additional improvements including stable production Turbopack, Cache Components, and proxy.ts. If you are already on Next.js 15, upgrading to 16 is worthwhile and the codemod handles most of the work.
Technologies

Stay up-to-date
Be updated with all news, products and tips we share!
On this page
- The biggest breaking change: Async Request APIs
- Caching is now uncached by default
- React 19 support
- Turbopack Dev is now stable
- The new <Form> component
- unstable_after() for post-response work
- instrumentation.js is now stable
- Server Actions security improvements
- next.config.ts TypeScript support
- Static Route Indicator
- Breaking changes summary
- Should you upgrade to Next.js 15 or go straight to 16?
- How to upgrade to Next.js 15
- Bring Your Ideas to Life π
- FAQs

