Next.js 16.4

Gedurende de 16.x releases hebben we een nieuw programmeermodel geïntroduceerd dat veel van de frustraties wegneemt die gebruikers vanaf het begin hadden met de App Router:

  • Het zorgt voor snelle initiële ladingen, zelfs voor gepersonaliseerde pagina's.
  • Het geeft server-gerenderde apps onmiddellijke client-navigaties.
  • Het maakt caching opt-in, declaratief en combineerbaar.

Dit nieuwe programmeermodel wordt Cache Components genoemd en zal de standaard worden in Next.js 17.

Voor deze release raadden we het niet universeel aan, omdat er gevallen waren waarin het niet dezelfde kosten- en prestatiegaranties kon bieden als het vorige model. Deze release bevat belangrijke functies die deze gaten dichten.

Vanaf Next.js 16.4 bevelen we Cache Components aan als de beste keuze voor elke Next.js-app. Vanaf vandaag zullen alle nieuwe apps die zijn aangemaakt met create-next-app standaard Cache Components hebben ingeschakeld. Greenfield-projecten kunnen zonder voorbehouden profiteren van alle voordelen van het nieuwe model.

Voor bestaande apps hebben we geïnvesteerd in betere agentic tooling om codebases te helpen migreren naar het nieuwe model. Het nieuwe commando next upgrade --agent geeft agents versie-specifieke richtlijnen voor het upgraden van je app, en speciale Skills helpen agents bij de nodige refactorings om Cache Components te adopteren.

Next.js 16.4 bevat daarnaast verschillende out-of-the-box verbeteringen voor alle Next.js-apps, waaronder een lager geheugengebruik en kleinere schijfgrootte in dev, kortere compileertijden, kleinere productie-bundels en React 19.3.

Hieronder volgt een volledig overzicht van wat je in deze release kunt verwachten, beginnend met Cache Components.

Wat zijn Cache Components?

Cache Components zijn een reeks functies waarmee je specifieke delen van je componentenboom kunt markeren als in aanmerking komend voor caching. Je kunt 'use cache' beschouwen als een versie van de Cache-Control HTTP-header op componentniveau:

import { cacheLife } from 'next/cache';

export default async function DashboardPage() {
  const currentUser = await getCurrentUser();
  return (
    <div>
      <p>Welkom, {currentUser.name}</p>
      <Suspense fallback={<Loading />}>
        <Projects userId={currentUser.id} />
      </Suspense>
    </div>
  );
}

async function Projects({ userId }) {
  'use cache';
  cacheLife('hours');
  const projects = await db.query.projects.findMany({
    where: eq(projectsTable.userId, userId),
  });
  return (
    <div>
      {projects.map((project) => (
        <p key={project.id}>{project.name}</p>
      ))}
    </div>
  );
}

Next.js interpreteert deze 'use cache' annotaties tijdens het renderen van je pagina's en cached de UI van je component in de browser (tijdens client-navigaties) en, optioneel, op de server (tijdens server-rendering, of vooraf tijdens de build).

Deze combineerbare annotaties stellen je in staat om client-side caching, volledig plugbare server-side caching en rendering op aanvraag (request-time rendering) te mengen binnen één enkele pagina. Ze vervangen de impliciete caching-behaviors van de vorige App Router-versies.

Wat is er nieuw in Cache Components?

In dit bericht verwijzen we met "Cache Components" naar het nieuwe programmeermodel, dat je vandaag al kunt gebruiken door twee flags in je Next.js-configuratie in te schakelen:

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
};

export default nextConfig;

Cache Components werden oorspronkelijk uitgebracht zonder Partial Prefetching, maar dit wordt nu als onderdeel van het model beschouwd.

Garanderen dat shells, prefetches of pagina's statisch zijn

Een van de kenmerkende functies van 'use cache' is de mogelijkheid om pagina's te bouwen die statische en dynamische inhoud samen streamen in één enkel antwoord van de server.

Bijvoorbeeld, je kunt de avatar van de huidige gebruiker weergeven naast een blogpost die verder statisch is prerendered:

export default function Page() {
  return (
    <>
      <UserAvatar />
      <Content />
    </>
  );
}

// Deze component rendert op het moment van aanvraag (request time)
async function UserAvatar() {
  const currentUser = await getCurrentUser();
  // ...
}

// Deze component is statisch prerendered
async function Content() {
  'use cache';
  await fetch('...');
  // ...
}

Next.js kan de prerenderde blogpost uit de cache serveren (zoals uit de /public map of een CDN) en de UserAvatar renderen op het moment van aanvraag, allemaal in hetzelfde HTTP-antwoord.

Hoewel deze flexibiliteit krachtig is, wil je soms een app bouwen met volledig statische pagina's. In die gevallen kan één dynamische component de prestaties of kosten van een verder geoptimaliseerde site verslechteren.

In Next.js 16.4 biedt ensureStatic een eenvoudige manier om te garanderen dat de shell, prefetch of volledige navigatie van een route statisch is. Hiermee voorkom je dat een dynamische component per ongeluk in een route terechtkomt.

Als we bijvoorbeeld willen afdwingen dat de blogpost-pagina uit het bovenstaande voorbeeld altijd statisch is, en dat het toevoegen van een dynamische component zoals UserAvatar onmogelijk moet zijn, kunnen we export const ensureStatic toevoegen aan de route:

export const ensureStatic = 'navigation';

export default function Page() {
  return (
    <>
      <UserAvatar /> {/* 🔴 Deze component zorgt dat de build faalt */}
      <Content />
    </>
  );
}

Door ensureStatic op "navigation" in te stellen, zal Next.js de build laten mislukken als er dynamische inhoud in deze pagina wordt opgenomen.

Naast "navigation" (de meest restrictieve vorm), kun je ensureStatic ook instellen op:

  • "prefetch": Om te garanderen dat links met expliciete prefetching naar deze route alleen statische inhoud ophalen.
  • "shell": Om te garanderen dat alleen statische inhoud wordt opgehaald wanneer deze route voor het eerst wordt ontdekt.

Je kunt ensureStatic ook toevoegen aan een layout om dezelfde garanties toe te passen op alle pagina's binnen die layout. Bijvoorbeeld in de root layout:

// app/layout.tsx
export const ensureStatic = 'navigation';

export default async function RootLayout({ children }) {
  // ...
}

Inhoud uitsluiten van een prefetch

Prefetching is een krachtige manier om de UX te verbeteren. Door <Link prefetch> of useRouter().prefetch() te gebruiken, kun je laadschermen elimineren door de cached UI van een pagina prerenderen voordat de eigenlijke navigatie plaatsvindt.

Neem als voorbeeld een eenvoudige e-mailapp met een Inbox die links naar berichten rendert:

async function Inbox() {
  const messages = await db.query.messages.findMany();
  return (
    <nav>
      {messages.map((message) => (
        <Link href={`/message/${message.id}`} key={message.id}>
          {message.subject}
        </Link>
      ))}
    </nav>
  );
}

En de Message-pagina, die een spinner toont bij het eerste laden en deze daarna cached in de browser:

// app/message/[id]/page.jsx
export default function Page({ params }) {
  return (
    <Suspense fallback={<Spinner />}>
      {params.then(({ id }) => (
        <Message id={id} />
      ))}
    </Suspense>
  );
}

async function Message({ id }) {
  const [message, thread] = await Promise.all([
    getMessage(id),
    getThread(id)
  ]);
  return (
    <>
      <p>{message.subject}</p>
      <div>{message.body}</div>
      {thread.map((message) => (
        <div key={message.id}>{message.body}</div>
      ))}
    </>
  );
}

async function getMessage(id) {
  'use cache';
  return db.query.messages.findFirst({ where: eq(messages.id, id) });
}

async function getThread(id) {
  'use cache';
  return db.query.messages.findMany({
    where: eq(messages.threadId, id),
    orderBy: asc(messages.createdAt),
  });
}

Om de initiële laadtijd te elimineren, kunnen we prefetch toevoegen aan de links in de Inbox. Echter, dit betekent dat elke zichtbare link de volledige discussie (thread) vooraf laadt, wat kostbaar kan zijn voor de servers.

In Next.js 16.4 kunnen we dit oplossen. De nieuwe navigatie-API stelt je in staat om het laden van cached inhoud tijdens een prefetch uit te sluiten, waardoor het wordt uitgesteld tot de eigenlijke navigatie plaatsvindt.

In het voorbeeld kunnen we de Thread in een nieuwe component plaatsen en await navigation() toevoegen:

import { navigation } from 'next/cache';

async function Message({ id }) {
  const message = await getMessage(id);
  return (
    <>
      <p>{message.subject}</p>
      <div>{message.body}</div>
      <Suspense fallback={<Spinner />}>
        <Thread id={id} />
      </Suspense>
    </>
  );
}

async function Thread({ id }) {
  await navigation();
  const thread = await getThread(id);
  return (
    <>
      {thread.map((message) => (
        <div key={message.id}>{message.body}</div>
      ))}
    </>
  );
}

Nu rendert de Message-pagina alleen het eerste bericht tijdens een prefetch, en wacht hij op de volledige navigatie om de rest van de thread uit de database te laden.

Naast navigation() is er ook prefetch() toegevoegd, die je kunt await om cached inhoud uit te sluiten die anders in de shell van een route zou worden opgenomen. Dit stelt je in staat om een balans te vinden tussen eager en lazy rendering.

Nieuwe agent-functies

Next.js investeert in agent-tooling om apps veilig en up-to-date te houden.

Agent upgrades

De nieuwe optie --agent voor next upgrade helpt je agent om je app van begin tot eind te upgraden. Het controleert de geïnstalleerde versie, selecteert een doelenrelease en bereidt migratiegidsen, codemods en verificatiestappen voor.

Je kunt dit uitvoeren via de terminal:

npx next@canary upgrade --agent=latest

Om up-to-date te blijven, introduceert Next.js 16.4 experimental.agentUpgrade. Wanneer je next dev of next build uitvoert, zal Next.js je (of je agent) automatisch waarschuwen wanneer er een relevante upgrade beschikbaar is.

Dit kun je configureren in je Next.js-configuratie:

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    agentUpgrade: 'security',
  },
};

export default nextConfig;

De beschikbare policies zijn:

  • 'security' (standaard): Herinnert je aan upgrades die bekende kwetsbaarheden oplossen.
  • 'latest': Herinnert je aan nieuwere major- of minor-releases.
  • false: Schakelt upgrade-herinneringen uit.

Agent feedback

De nieuwe experimentele agent-feedback workflow stelt coding agents in staat om conceptrapporten op te stellen over frameworkfouten of onduidelijke documentatie, die je vervolgens kunt reviewen en verzenden naar het Next.js-team.

Dit is standaard ingeschakeld bij nieuwe apps. Voor bestaande apps kun je dit activeren via:

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    agentFeedback: true,
  },
};

export default nextConfig;

De agent is geïnstrueerd om broncode, logs, geheimen en projectspecifieke details weg te laten. Niets wordt verzonden totdat je expliciet op "Send feedback" klikt. Let op: agent-feedback vereist dat Next.js Telemetry is ingeschakeld en werkt niet in CI.

Verbeteringen voor alle apps

Kleinere disk cache grootte

In 16.4 verbruikt de disk cache van Turbopack 20–25% minder ruimte. De cache gebruikt nu Zstandard-compressie voor de grootste datablokken, terwijl LZ4 wordt behouden voor metadata om snelle lookups te garanderen.

Lazy server HMR

Voorheen kon het wijzigen van een gedeelde servermodule updates triggeren voor alle pagina's die je in de sessie had bezocht. In 16.4 compileert en past Turbopack server-updates alleen toe wanneer een aanvraag deze nodig heeft.

Turbopack shared runtime

Turbopack levert zijn runtime nu in één enkele chunk die over routes wordt gedeeld, wat de downloadgrootte vermindert en de cache hit rates verbetert.

Kleinere productie-bundels

Turbopack genereert in 16.4 kortere CSS Module klassennamen in productie. Daarnaast wordt export mangling gebruikt om interne JavaScript-exportnamen te verkorten, wat de bundelgrootte verder vermindert.

React 19.3

Next.js 16.4 wordt geleverd met React 19.3, wat stabiele View Transitions en Fragment Refs introduceert, de nieuwe browser() API, en meer.

Nieuwe experimentele functies

Rust React Compiler

De experimentele Rust-versie van de React Compiler draait nu direct in Next.js in plaats van via Babel. In 16.4 is een nieuwe snelle check toegevoegd om bestanden over te slaan die geen optimalisatie nodig hebben. De geheugengebruik is met 30% verminderd en de compileertijd met 15%.

Configuratie:

// next.config.ts
const nextConfig: NextConfig = {
  reactCompiler: true,
  experimental: {
    turbopackRustReactCompiler: true,
  },
};

Disk cache cleanup

Een experimentele garbage collector verwijdert ongebruikt compilatiewerk uit het geheugen en de disk cache, wat nuttig is tijdens lange dev-sessies.

Configuratie:

// next.config.ts
const nextConfig: NextConfig = {
  experimental: {
    turbopackGc: true,
  },
};

Lazy dynamic imports

Je kunt nu kiezen om client-side dynamic imports pas te compileren wanneer de browser ze aanvraagt, wat de initiële compilatielast vermindert.

Configuratie:

// next.config.ts
const nextConfig: NextConfig = {
  experimental: {
    turbopackLazyDynamicImports: true,
  },
};

Worker threads

Turbopack kan nu tools zoals Babel en PostCSS uitvoeren binnen een enkel proces via worker threads, in plaats van via aparte Node.js-processen over sockets. Dit vermindert het geheugen- en CPU-gebruik.

Configuratie:

// next.config.ts
const nextConfig: NextConfig = {
  experimental: {
    turbopackPluginRuntimeStrategy: 'workerThreads',
  },
};

(Opmerking: Op Node.js 24.13.1 en nieuwer valt Next.js momenteel terug op child processes vanwege een Node.js bug.)

Extra roots en ondersteuning voor global virtual store

Next.js 16.4 kan symlinked dependencies buiten de projectroot volgen. Dit vergemakkelijkt het werken met gelinkte lokale pakketten en integreert handmatig met global virtual stores in pnpm, Bun, Nub, en aube.

Configuratie:

// next.config.ts
import path from 'node:path';

const nextConfig: NextConfig = {
  experimental: {
    turbopackAdditionalRoots: {
      linkedPackages: { path: path.join(__dirname, '../packages') },
    },
  },
};

Turbopack Bundle Analyzer

De Bundle Analyzer is uitgebreid met:

  • Een route-samenvatting homepage die de grootste client routes markeert.
  • Een tabelweergave om snel te sorteren op de grootste bijdragers aan resources.
  • Automatische snapshots en diff-mogelijkheden tussen bundels.
  • Onderscheid tussen modules op het kritieke renderpad.

Er is ook een experimentele next-bundle-optimizer agent skill beschikbaar. Om deze te gebruiken:

  1. Upgrade naar 16.4.
  2. Voer uit: npx skills add vercel/next.js --skill next-bundle-optimizer.
  3. Gebruik /next-bundle-optimizer in je AI-agent.

Feedback en community

Je kunt je app upgraden via de CLI: npx next@canary upgrade --agent=latest

Of handmatig: npm install next@latest

Deel je feedback via GitHub Discussions, GitHub Issues of de Discord Community.

Bijdragers

Next.js is het resultaat van het gezamenlijke werk van duizenden individuele ontwikkelaars. Deze release is mogelijk gemaakt door het Next.js team, het Turbopack team en een grote groep externe bijdragers.