arrow to navigation
Aleksander
Jess
Technical
12.09.2024 | 5 min

Next.js 15. What’s New, What Changed, Breaking Changes.

Next.js has received an update to version 15, and it received features we were all waiting for.

Next.js 15. What’s New, What Changed, Breaking Changes. - 2024 46
Table of Contents
  • Intro
  • What’s New
  • Next.js 15 Breaking Changes
  • Conclusion

Intro

Special thanks to Łukasz Gajownik for helping out with this blog post.

Next.js is the most popular full-stack React framework out there, and it’s getting its fifteenth major update. While it won’t be as revolutionary as the previous one, which introduced React Server Components among others. It will, however, bring many goodies designed to make working with web apps easier, and more pleasant. Even after fifteen updates, however, the base rules didn’t change, and the framework still stays true to them: “zero setup and using the file system as an API; only using JavaScript, with everything acting as a function; automatic server-rendering and code-splitting; data-fetching is up to the developer; anticipation is the key to performance; and simple deployment.”

What’s New

React 19

React 19 (see the documentation for the version 19 here) is perhaps the most significant change this time around. This new version brings some changes that you might or might not heard about, including:

If you have a weird feeling you have seen some of these before, then that’s because you have, quite possibly in Next 14. This time around, Meta is bringing the support for these features to the wider audience, such as non Next.js users.

One underrated change is the full support for custom elements. React previously struggled with Web Components, but it’s all in the past now, as Meta’s JS library boasts full support.

React Compiler

Before:

export default function Example() {

const [value, setValue] = useState("");

const handleChange: ChangeHandler<HTMLInputElement> = (e) => {

setValue(e.target.value)

}

return (

<div>

<label>Enter the text here</label>

<input value={value} onChange={handleChange} />

</div>

);

}

After:

function Example() {

const $ = _c(4);

const [value, setValue] = useState("");

let t0;

if ($[0] === Symbol.for("react.memo_cache_sentinel")) {

t0 = (e) => {

setValue(e.target.value);

};

$[0] = t0;

} else {

t0 = $[0];

}

const handleChange = t0;

let t1;

if ($[1] === Symbol.for("react.memo_cache_sentinel")) {

t1 = <label>Enter the text here</label>;

$[1] = t1;

} else {

t1 = $[1];

}

let t2;

if ($[2] !== value) {

t2 = (

<div>

{t1}

<input value={value} onChange={handleChange} />

</div>

);

$[2] = value;

$[3] = t2;

} else {

t2 = $[3];

}

return t2;

}

Compiling framework/library code isn’t a new concept. Svelte, Vue, Solid, and others, have done it for a long time already. The React team caught wind of that some time ago, and first introduced the compiler during a React talk “React without memo” in 2021. About 3 years later, we can finally give the compiler a shot, and we can offload a lot of busy work that includes memoization. The ability to let the compiler perform optimizations will also mean our code should be simpler, while it could turn out that our apps will become faster. If you want to take a quick peek at the before and after code, you can jump in and have fun with the Compiler Playground.

React 19 Breaking Changes

For a full list of breaking changes, please refer to the blog post at 19.react.dev/blog.

Incremental Adoption of Partial Prerendering (Experimental)

Partial prerendering isn’t an entirely new feature - it was introduced in Next.js 14. The novelty here is the fact that now the feature can be adopted incrementally. This way, if you add “experimental_ppr” route config option to your page, you will opt the whole page into Partial Prerendering.

Why would you want to do it? Partial prerendering lets you combine static content with the dynamic one. Prerendering only a part of the page is a compromise between keeping data fresh as possible, and faster websites, reduced server load, and SEO.

“next/after” (Experimental)

The new module allows you to execute code after a response. Previously, if you deployed your site to a serverless hoster, running a function right after loading wasn’t as straightforward. Quoting the blog, “[d]eferring the work after responding to the user poses a challenge because serverless functions stop computation immediately after the response is closed.”

That’s why the Next.js team solved this issue by introducing “after()”. Why would you need it? It’s useful for “logging, analytics, and other external system synchronization”.

Caching Changes

Previously, Next.js App Router had highly opinionated caching defaults. Caching “fetch”, Client route changes, and GET route handlers requests was opt-out: they were all cached by default. Starting from this release, the caching behavior will be opt-in instead.

In other words, in fetch “no-store is used by default if a cache option is not provided. This means fetch requests will not be cached by default”. GET route handlers will not be cached unless you “opt into caching using a static route config option such as export dynamic = 'force-static'.” Lastly, to opt into router caching, set the route config option of “staleTime” to your preferred values for both dynamic and static pages.

For web app developers this means that you will have to consciously set cache times on your own, meaning you, in theory, get more control over caching.

Next.js 15 Breaking Changes

As with almost any major update, there are also breaking changes. In this case the few most important ones are:

  • Minimum React version is now 19 RC
  • Removed squoosh in favor of sharp as an optional dependency
  • Changed default “Content-Disposition” to “attachment”
  • Enable swcMinify, missingSuspenseWithCSRBailout, and outputFileTracing behavior by default and remove deprecated options.

For the full list, refer to the list here.

Conclusion

The latest update to Next.js 15 is an evolution, and not a revolution. This time around, the major update will bring many changes that will help with SEO. We can optimize client bundle, opt into partial prerendering page by page, and minifying with SWC is enabled by default. From the point of view of a company that develops big web apps, the introduction of the compiler is perhaps the most important. It will be much easier to create efficient apps thanks to the automatic memoization.

If you want to talk about creating a custom web app in Next.js for you, then don’t hesitate to contact us by clicking this link.

Let's Work Together and Shape the Future
Contact us