
Next.js 15 Async Request API and Caching Policy Changes: What's Changed and How to Adapt
With the release of Next.js 15, there have been significant changes to how server components and route handlers are handled. Things like cookies, headers, and URL parameters, which were previously accessed synchronously, have now been converted to an asynchronous API. Additionally, the default fetch caching policy, which was a point of contention for many developers, has been completely overhauled.
Teams that have been building web services using the App Router will likely encounter build errors or runtime warnings during the migration. Here, I'll break down the background behind these changes and how your coding practices should shift.
What Has Changed
There are two core changes. First, access to request-related objects now returns a Promise, and second, the default caching for fetch requests and GET route handlers has been disabled.
In Next.js 13 and 14, you would call cookies() or headers() as synchronous functions to retrieve values directly. The params and searchParams props received by page or layout components were also standard objects. As of Next.js 15, all of these are now Promise-based, so you must use await to access them.
Regarding caching, up until Next.js 14, fetch requests were automatically cached permanently (force-cache) if the developer didn't set otherwise. This caused confusion for many, as data wasn't updating in real-time. Next.js 15 has abandoned this behavior in favor of the web standard, defaulting to no-store to fetch fresh data on every request.
Why Change Sync APIs to Async?
While it might seem like extra work to add an await to your code, the Vercel team redesigned this interface to optimize server rendering and streaming efficiency.
Previously, if a component tried to read cookies or headers while the server was beginning to render a page, the entire server-side rendering process would wait until the actual request headers arrived. By moving to an asynchronous API, the framework can stream static layouts or upper-level components that don't depend on data before the request headers are fully evaluated.
There is also a strong intention to clearly define the boundary between static and dynamic rendering. Using async handlers allows for precise tracking of which components rely on request context at runtime, serving as a foundation for future compiler optimizations and Partial Prerendering.
Practical Coding: cookies() and params
In a Next.js 15 environment, you must explicitly use await when calling for cookies or accessing parameters in dynamic routes.
In Next.js 15, trying to destructure directly like const \{ id \} = params; will trigger runtime warnings in development mode. You can run the official migration codemod to apply await to existing parameter and header calls throughout your components.
Changes to Fetch Defaults and Caching Strategy
With the default caching disabled, Next.js fetch now behaves the same as the native browser fetch, sending a new request to the backend server every time. Likewise, GET requests in route handlers will no longer be static by default and will execute every time.
If you want to maintain strong static caching for rarely changing external API data, you will need to specify the options explicitly.
For dashboards or user-specific pages where real-time accuracy is critical, you no longer need to manually attach \{ cache: 'no-store' \}, which significantly reduces bugs related to unintended stale cache. Conversely, if you operate pages that handle frequently requested common master data or content, be aware that cache misses could increase backend traffic, so it is a good idea to check if you need the force-cache option.
