I’ve been working with Next.Js for a quite a while and have been watching its development with interest all this time. Last week I was happy attended Next.js Conf in San Francisco. Perficient was proudly sponsoring of this event therefore I represented our Sitecore Practice along with David Lewis – my peer colleague from the Optimizely Practice
Vercel released new version 15 of Next.js framework. That was truly innovative day and I’d like to share my takeaways from the event about this new version.
Vercel seriously worked on mistakes
The next.js team previously made some bad decisions, they rushed releases, held opinionated views despite the community: rewriting fetch, hard caching, lots of bugs, you name it.. and once again -ignoring community requests. It took almost a year to realize that would not lead somewhere and to address the actual problems. Now, with version 15, finally, there is a feeling that the framework is solving the community’s problems. Again, as it did in the past.
React 19
Here we get quite weird situation happening. More than half a year passed since the release candidate of React.js, but the stable version has not yet been published. React.js stable version being delayed directly affects plans of Next.js. since both are quite tied. Therefore next.js currently uses the RC version of React.js but that is only partly true statement. In fact, next.js currently uses two React.js configurations:
- the 19th canary version for App Router and
- the 18th version for Pages Router
It is interesting that at one point they wanted to include the 19th version for Pages Router, but later rolled back these changes. The full support for the 19th version of React.js is promised after the release of its stable version.
Form component
This next.js innovation is in fact already familiar form from react-dom
, but with some improvements. You benefit from Next.Js implementation primarily in cases when a successful form submission involves a transition to another page. In that case, the loading.tsx
and layout.tsx
abstractions for the following page will get preloaded.
import Form from 'next/form' export default function Page() { return ( <Form action="/search"> {/* On submission, the input value will be appended to the URL, e.g. /search?query=abc */} <input name="query" /> <button type="submit">Submit</button> </Form> ) }
Developer Experience (DX)
When talking about next.js, we can’t help but mention the developer experience. In addition to the typical “Faster, Higher, Stronger†statements, there were several useful improvements in DX
- Long-awaited support for ESlint v9. Next.js never supported ESlint v9. This is despite the fact that both eslint (v8) and some of its own dependencies were already marked as deprecated. Because of that developers were essentially forced to keep deprecated packages.
- The error interface in next.js – which is already clear and convenient – was slightly improved:
- Added a button to copy the call stack;
- Added the ability to open the source of the error in the editor on a specific line.
- Added Static Indicator – an element in the corner of the page showing that the page is built in static mode. The pre-built page indicator has been with us for years so it was slightly updated and adapted for App Router.
- Also added a directory with debug information – .next/diagnostics. That’s where one can find information about the build process and all errors that occur (sometimes helps to parse problems).
Versioning the documentation
A very useful change: finally, you can view different versions of the documentation. But why is that so important for the Development Experience?
Updating next.js due to major changes is often quite a difficult task. For this reason one can still see more than 2 million downloads for version 12 and more than 4 million for version 13 monthly. Therefore users require documentation for their particular versions, since the recent documentation could be half-changed.
Turbopack
Probably the biggest news:
- Turbopack is fully finished for development mode! “100% of existing tests ran without errors with Turbopackâ€
- Now the turbo team is working on the production version, progressively going through the tests and covering them all (currently about 96%)
Turbopack also adds new features:
- Setting a memory limit for a Turbopack build;
- Tree Shaking (in other words that is removal of the unused code):
-
const nextConfig = { experimental: { turbo: { treeShaking: true, memoryLimit: 1024 * 1024 * 512 // bytes (512MB) }, }, }
These turbopack change alone reduced memory usage by 25-30% and speeded up heavy page assembly by 30-50%.â€
- Fixed significant issues with styles. In version 14, there were often situations when the styles were broken in order during navigation, and because of this, style A became higher than style B, then lower. This changed their priority and, accordingly, the elements looked different.
- The next long-awaited improvement. Now you can write the configuration in TypeScript, and the file correspondingly would be next.config.ts:
import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* here goes you config */ }; export default nextConfig;
Same strongly-typed syntax as usual, but very nice to have, finally!
- Another interesting innovation is retrying a failed page generation before actually failing the build for static pages. If the page fails the assembly for the connectivity issues, it will try it again:
const nextConfig = { experimental: { staticGenerationRetryCount: 3, }, }
Framework API changes
These are typically the most painful parts of next.js updates. The version 15 also has critical updates.
A set of framework APIs have become asynchronous. And these are the most framework-centric abstractions, namely:
cookies
,headers
,params
and- searchParams (also called Dynamic APIs).
import { cookies } from 'next/headers'; export async function AdminPanel() { const cookieStore = await cookies(); const token = cookieStore.get('token'); // ... }
The changes are big indeed, but the Next.js team suggests one could update to the new APIs automatically by calling their codemod
:
npx @next/codemod@canary next-async-request-api .
Caching
In my opinion, that is where the most important changes have happened. And the most important news is that Caching is now disabled by default!
Let’s take a look on what’s changed:
- Actually, fetch now uses the no-store value by default instead of force-cache;
- API routes use force-dynamic mode by default (previously it was force-static by default);
- Caching in the client router has also been disabled. Previously, if a client visited a page within the path, it was cached on the client and remained in this state until the page reload. Now the current page will be loaded each time. This functionality can be altered via next.config.js:
const nextConfig = { experimental: { staleTimes: { dynamic: 30 // defaults to 0 }, }, }
- Moreover, even if client caching is enabled, it most likely will be updated at the correct time. Namely, if the enabled page cache on the server expires.
- Server components are now cached in development mode. Due to this, updates in development are faster.
- Following the above, one can reset the cache by just reloading a page or can also completely disable the functionality via next.config.js:
const nextConfig = { experimental: { serverComponentsHmrCache: false, // defaults to true }, }
- You can control the “Cache-Control†header which was previously always overwritten with the internal values ​​of next.js. This caused artifacts with caching via CDN;
- Â next/dynamic caches modules for reuse, rather than loading again each time;
Partial Prerendering (PPR)
This could be the main teaser of the release. PPR is a page assembly mode, in which Next.Js prerenders and caches as much of the route as possible,. while some individual elements are built on each request. In this case, the pre-assembled part is immediately sent to the client, and the remaining are loaded dynamically.
The feature existed already six months ago in the release candidate as an experimental API. Previously PPR was enabled for the entire project, but since now it one can enable it for each segment (layout or page):
export const experimental_ppr = true
Another change is Partial Fallback Prerendering (PFPR). Due to this improvement, the pre-assembled part is immediately sent to the client, and the rest are loaded dynamically. At this time, a callback component is shown in place of the dynamic elements.
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> </> }; }
Instrumentation
Instrumentation comes as a stable API. The instrumentation file allows users to affect Next.js server lifecycle. Works universally with all Pages Router and App Router segments.
Currently, instrumentation supports hooks:
- register – called once when initializing the next.js server. Can be used for integration with monitoring libraries (OpenTelemetry, datalog) or for specific project tasks.
- onRequestError – a new hook called on all server errors. Can be used for integration with error tracking libraries (Sentry).
Interceptor
Interceptor is route-level middleware. It feels as something like a full-fledged existing middleware, but, unlike the one:
- Can work in node.js runtime;
- Works on the server, therefore has access to the environment and a single cache;
- Can be added multiple times and is nesting inherited (like middleware worked when it was in beta);
- Works, among other things, for server functions.
In this case, when creating an interceptor file, all pages underneath the tree become dynamic.
- If we keep Vercel in mind, now middleware will be effective as a primary simple check at the CDN level (so that it could immediately return redirects if the request is not allowed), and interceptors will work on the server, doing full checks and complex operations.
- For the self-host, apparently, such a division will be less effective since both abstractions work on the server. Perhaps it will be enough just to use only interceptor.
V0 is Vercel’s new Generative UI
Last but not the least, you can use v0 on in other words – a Generative UI, which combines the best practices of frontend development with the full potential of generative AI. Currently v0 landed Beta, and I was happy to try it in action at the event. Glad to say, it is indeed powerful and knowledgeable – it managed to deliver me the configuration for Sitecore from the first prompt!
Finally, I am happy to conclude that out toolbelt has been replenished with the new practical tools which allow to deliver the ultimate solutions without a struggle of reinventing the bicycleâ€.
Well done, Vercel!
Source: Read MoreÂ