logoNext.js 15
hero

Exploring Next.js 15 RC

In this blog, we will explore the Next.js 15 RC to test the latest features for the upcoming stable release of Next.js. The first release candidate for Next.js 15 RC was rolled out on May 23, 2024. This means we can examine all the new development, production, and caching features.

The latest updates include several key features organized into stable and experimental improvements.

Stable improvements

  • Support for React 19 RC
  • Hydration error improvements
  • Caching improvements
  • Updated create-next-app
  • Bundling external packages
  • Experimental features
  • React compiler
  • Partial prerendering
  • Next/After

What is Next.js?

Next.js is a versatile, open-source React framework developed by Vercel. It is designed to easily build fast, SEO-friendly, and user-friendly web apps. It elegantly combines server-side rendering, static site generation, and client-side rendering capabilities, making it an outstanding choice for modern web development.

Its features include automatic code splitting, efficient routing, API routes, and an optimized production build, contributing to its performance and scalability. Moreover, Next.js prioritizes developer experience, offering fast refresh for a more seamless coding process. This ensures that it caters to the end user's needs and those creating the apps.

How do I upgrade to the latest Next.js version?

To upgrade to the latest version of Next.js (version 15 RC), use the following command with your preferred package manager:

NPM

npm i next@rc react@rc react-dom@rc eslint-config-next@rc

Yarn

yarn add next@rc react@rc react-dom@rc eslint-config-next@rc

Please note that the minimum required versions for react and react-dom are 19. For more information on version upgrading, refer to the official documentation.

React 19 RC

Before upgrading to React 19 RC, please check the new features and updates by visiting our blog.

With the unveiling of React 19 RC, the Next.js App Router is being developed on the React canary channel specifically for frameworks. This allows developers to utilize and provide input on the latest React APIs ahead of the official v19 launch. Next.js 15 RC will be compatible with React 19 RC, bringing forth novel features for both client-side and server-side environments, including Actions.

For more information, please refer to the React 19 upgrade guide.

React Compiler

The React Compiler is a new experimental compiler developed by the React team at Meta. It leverages its understanding of plain JavaScript semantics and the Rules of React to analyze and optimize your code. This deep understanding enables the compiler to automatically apply optimizations, reducing the need for manual memoization techniques like useMemo and useCallback. As a result, your code becomes more concise, easier to maintain, and less prone to errors.

With Next.js 15, React Compiler support has been added. However, the React Compiler can currently only be used in Next.js through a Babel plugin.

Installation

npm install babel-plugin-react-compiler

Add the experimental.reactCompiler option in the next.config.js file.

const nextConfig = {
  experimental: {
    reactCompiler: true,
  },
};
module.exports = nextConfig;

Using the experimental option ensures support for the React Compiler in the following areas: App Router, Pages Router, Webpack, and Turbopack.

Key benefits of the React Compiler

  • Automatic optimization: The compiler identifies opportunities to optimize your code, improving performance without manual effort.
  • Reduced boilerplate: Lessens the need for manual memoization, leading to cleaner and more concise code.
  • Improved maintainability: Simplifies code, making it easier to understand and modify.
  • Error prevention: Helps avoid common performance pitfalls related to unnecessary re-renders.

Note: The React Compiler is currently in an experimental phase, and its features and capabilities may evolve. It’s recommended that you stay updated with the latest developments and consider using it cautiously in your projects.

Hydration error enhancements

Next.js 15 has improved the way hydration errors are displayed. Hydration errors happen in Next .js when there is a mismatch between the HTML rendered on the server and the HTML rendered in the client during the initial load. This mismatch can be caused by text, incorrect HTML nesting, and browser-specific code. With the new improvements, when a hydration error occurs, the source code of the error is displayed, along with suggestions on how to fix the issue.

For more details, refer to the official Next.js documentation on Hydration error improvements.

Caching updates

Caching in Next.js is essential for improving performance and reducing server load. The Next.js App Router was introduced with opinionated caching defaults, designed to provide optimal performance by default with the ability to opt out when necessary.

In Next.js 15, the default behavior for caching fetch requests, GET Route Handlers, and the Client Router Cache has been updated. Previously, these were cached by default, but now they are uncached by default. If you prefer the old behavior, you can still opt into caching. Note that layouts and loading states will continue to be cached and reused during navigation.

Client router cache behavior in Next.js 15

An experimental staleTimes flag was introduced to allow custom configuration of the Router Cache in Next.js 14.2.0. This flag still remains accessible in Next.js 15. However, we are changing the default behavior to a staleTime of 0 for Page segments. This means that as you navigate your app, the client will always reflect the latest data from the Page component(s) that become active as part of the navigation. However, there are still important behaviors that remain unchanged:

  • Shared layout data avoids server re-fetching, supporting partial rendering.
  • Browser back/forward navigation restores cache, including scroll position.
  • Loading.js is cached for 5 minutes or per staleTimes.static config.

You can opt into the previous client router cache behavior by setting the following configuration:

const nextConfig = {
  experimental: {
    staleTimes: { dynamic: 30 },
  },
};
module.exports = nextConfig;

Create-next-app enhancements

Let’s discuss the improvements in create-next-app. When you launch the app, it now has a new landing page and provides a prompt for choosing Turbopack when creating the Next app.

The Next.js 14 release introduced an incremental bundler called Turbopack, which is written in Rust and designed to optimize JavaScript and TypeScript. It has been integrated into Next.js to improve development performance.

In the Next.js 15 RC, when running the create-next-app command, a new prompt asks whether you would like to enable Turbopack for local development. The default setting is No.

✔ Would you like to use Turbopack for next dev? … No / Yes

The –turbo flag can be used to activate Turbopack.

npx create-next-app@rc –turbo

To simplify the process of getting started on a new project, a new –empty flag has been included in the CLI. This flag removes unnecessary files and styles, resulting in a minimal Hello world page.

npx create-next-app@rc –empty

Improving the bundling of external libraries (stable)

Integrating external libraries can enhance an app’s initial load performance. By default, the App Router bundles external libraries, but you can exclude particular libraries using the serverExternalPackages configuration option.

In the Pages Router, external libraries are not bundled by default. However, you can specify a list of libraries you wish to bundle through the transpilePackages option, which requires individual package specifications.

To streamline configurations across both the App and Pages routers, a new option named bundlePagesRouterDependencies was introduced. This setting will align with the App Router’s default behavior of automatically bundling external libraries. The serverExternalPackages option remains available to exclude specific libraries as needed.

Response execution with next/after (experimental)

When handling a user request, the server usually focuses on tasks directly related to generating the response. However, additional tasks like logging, analytics, or synchronizing with external systems often need to be performed.

These secondary tasks should ensure the user’s response is timely. Deferring such tasks can be challenging because serverless functions typically stop execution as soon as the response is sent.

The after() API, currently experimental, addresses this issue by allowing you to schedule tasks to run after the response has been streamed. This enables secondary tasks to execute without blocking the primary response.

To enable this feature, add experimental.after to your 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';export default function Layout({ children }) {
  // Secondary task.
  after(() => {
    ....
  });

  // Primary task.
  return <>{children}</>;
&#125 ;

Partial Prerendering

Partial Prerendering, or PPR, was rolled out in Next.js 14. It is an optimization that blends static and dynamic rendering on the same page.

By default, Next.js uses static rendering unless dynamic functions like cookies(), headers(), or uncached data requests are used, which switch the entire route to dynamic rendering. With PPR, you can wrap dynamic UI components in a Suspense boundary. When a new request is made, Next.js immediately serves a static HTML shell and then renders and streams the dynamic parts within the same HTTP request.

To facilitate incremental adoption, we've added an experimental_ppr route config option to enable PPR for specific Layouts and Pages. Refer to the following code example.

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 this new option, set the experimental.ppr config to incremental in your next.config.js file.

const nextConfig = {
  experimental: {
    ppr: 'incremental',
  },
};
module.exports = nextConfig;

Once all segments have PPR enabled, setting the ppr value to true will be safe, enabling it for the entire app and all future routes.