Next.js 15 Release Candidate: Explore the New Features and Enhancements
The Next.js 15 Release Candidate (RC) is here, offering developers an exciting opportunity to explore and test the latest features before the official stable release. This pre-release version brings significant advancements, making it a crucial step in the evolution of the popular React framework. Below, we dive into the key updates, enhancements, and experimental features that are shaping the future of Next.js.
One of the most anticipated features of the Next.js 15 RC is its support for the React 19 Release Candidate. This integration ensures that developers can harness the latest improvements in React while building applications with Next.js. Among these enhancements is the experimental React Compiler, designed to optimize React code during the build process. This new compiler aims to reduce bundle sizes and improve overall application performance, making it a vital tool for developers focused on efficiency.
Additionally, significant improvements have been made to hydration error handling, addressing issues that can occur when React attempts to rehydrate server-rendered HTML on the client side. These improvements contribute to a more seamless user experience, reducing the likelihood of errors that can disrupt the application's functionality.
React Compiler also powers an eslint plugin. The eslint plugin can be used independently of the compiler, meaning you can use the eslint plugin even if you don’t use the compiler.
npm install eslint-plugin-react-compiler@experimental
Then, add it to your eslint config:
module.exports = {
plugins: [
'eslint-plugin-react-compiler',
],
rules: {
'react-compiler/react-compiler': "error",
},
}
The eslint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase.
You don’t have to fix all eslint violations straight away. You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler.
Next.js 15 introduces a notable shift in caching behavior, particularly concerning fetch requests, GET Route Handlers, and client navigations. In previous versions, these elements were cached by default, which could sometimes lead to stale data being displayed to users. With this release, caching is no longer enabled by default, ensuring that applications always serve the most up-to-date content.
This change is especially beneficial for applications that rely on dynamic content or frequent data updates. Developers can still opt-in to caching if needed, but the default setting now prioritizes fresh data, aligning with modern web application best practices.
Next.js App Router initially introduced opinionated caching defaults aimed at delivering the most performant experience out of the box, with options to opt-out when necessary.
After gathering feedback, we took a closer look at our caching heuristics, particularly how they interact with features like Partial Prerendering (PPR) and third-party libraries that utilize fetch.
With the release of Next.js 15, we're adjusting our approach by changing the default behavior for fetch requests, GET Route Handlers, and the Client Router Cache from being cached by default to being uncached by default. If you prefer the previous behavior, you can still opt-in to caching.
We're committed to enhancing caching capabilities in Next.js over the coming months, and we'll provide more information in the Next.js 15 GA announcement.
In Next.js 15, the flag for modifying caching behavior is still accessible, but we've changed the default setting to a staleTime of 0 for Page segments. This means that as users navigate through your app, the client will always display the most current data from the active Page components.
However, some key behaviors remain the same:
If you prefer the previous caching behavior of the Client Router, you can opt-in by setting the appropriate configuration.
const nextConfig = {
experimental: {
staleTimes: {
dynamic: 30,
},
},
};
module.exports = nextConfig;
In Next.js 14, we introduced Partial Prerendering (PPR), an optimization that seamlessly integrates static and dynamic rendering on the same page.
By default, Next.js uses static rendering unless you include dynamic functions like cookies(), headers(), or uncached data requests. These APIs automatically opt an entire route into dynamic rendering. However, with PPR, you can enclose any dynamic UI component within a Suspense boundary. When a new request is received, Next.js instantly serves a static HTML shell, then renders and streams the dynamic portions in the same HTTP request.
To make the transition easier, we've added an experimental_ppr route configuration option. This allows you to selectively opt specific Layouts and Pages into PPR, enabling incremental adoption of this feature.
import { Suspense } from "react"
import { StaticComponent, DynamicComponent } from "@/app/ui"
export const experimental_ppr = true
export default function Page() {
return {
<>
<StaticComponent />
<Suspense fallback={...}>
<DynamicComponent />
</Suspense>
</>
};
}
To use the new option, you’ll need to set the experimental.ppr config in your next.config.js file to 'incremental':
const nextConfig = {
experimental: {
ppr: 'incremental',
},
};
module.exports = nextConfig;
Another exciting experimental feature in Next.js 15 is the next/after API, which allows developers to execute code after a response has finished streaming. This new API opens up possibilities for post-processing tasks, such as logging, analytics, or cleanup operations, without impacting the user experience.
By decoupling these tasks from the main response flow, the next/after API ensures that users receive content as quickly as possible, while still allowing developers to perform necessary backend operations. This feature is expected to be particularly useful in applications with complex server-side logic or those that require extensive post-response processing.
To use it, add experimental.after to next.config.js:
const nextConfig = {
experimental: {
after: true,
},
};
module.exports = nextConfig;
Then, import the function in Server Components, Server Actions, Route Handlers, or Middleware.
import { unstable_after as after } from 'next/server';
import { log } from '@/app/utils';
export default function Layout({ children }) {
// Secondary task
after(() => {
log();
});
// Primary task
return <>{children}</>;
}
The create-next-app command has also received significant updates in the Next.js 15 RC. The tool's design has been refreshed, making it more user-friendly and visually appealing. In addition to the design overhaul, a new flag has been introduced to enable Turbopack in local development.
Turbopack is a next-generation bundler that promises faster build times and improved performance during development. By enabling this feature, developers can experience these benefits firsthand, leading to a more efficient development process and quicker iteration cycles.
Finally, Next.js 15 RC introduces stable support for bundling external packages with new configuration options for both the App and Pages Router. This enhancement gives developers more control over how external dependencies are handled in their applications, allowing for better optimization and potentially smaller bundle sizes.
These new configuration options are designed to accommodate a wide range of use cases, from simple applications to complex projects with numerous dependencies. By offering more granular control over bundling, Next.js 15 ensures that developers can tailor their build process to meet the specific needs of their projects.