# Next.js 16.3 for dummies

> Instant navigations explained in plain English, plus our upgrade to 16.3, the cache components PR we parked, and the 341KB we cut instead.

**TL;DR:** Next.js 16.3 (stable since August 3, 2026) brings instant navigations (SPA-feel link clicks on a server-driven app), plus huge Turbopack memory cuts, native Node.js streams rendering, agent-first tooling, and a deprecated edge runtime. We upgraded this site to the preview in an afternoon, built the full instant-navigations adoption on a branch, then parked it because full SSG already navigates instantly. The thing that made our site feel faster was cutting 341KB of gzipped JavaScript with dynamic imports. An edit note covers the preview-to-stable diff and our build benchmarks.

**Published:** 2026-07-16 | **Updated:** 2026-08-11 | **Categories:** Next.js, Performance, Vercel
---

We've covered [Next.js 16](/blog/nextjs-16-for-dummies), [16.1](/blog/nextjs-16-1-for-dummies), and [16.2](/blog/nextjs-16-2-for-dummies) in this series, and now Vercel has started publishing what's coming in 16.3. The lead feature is instant navigations: clicking a link on a server-rendered site responds immediately, the way it does in a single-page app.

**16.3 went stable on [August 3](https://nextjs.org/blog/next-16-3).** We wrote this post against `16.3.0-preview.5` and it stands as written below; this note covers what changed between the preview and stable, and what we measured after bumping this site to `16.3.0`.

**New since the preview:**

- **The build cache is on by default.** The persistent Turbopack cache for `next build` graduated from `experimental.turbopackFileSystemCacheForBuild` to a default. Vercel reports up to 5.5x faster CI builds; our numbers are below.
- **Prefetch inlining.** Small prefetch payloads now get bundled together automatically. Apps upgrading from 16.2 saw [45% fewer prefetch requests on average](https://vercel.com/blog/vercel-supports-next-js-16-3), some over 70%.
- **Immutable static assets.** Hashed assets can be reused across deployments: 17% fewer CDN requests and 24% fewer bytes transferred for static content in Vercel's fleet numbers.
- **TypeScript 7 type checking.** The "faster TypeScript, experimentally" line from the grab bag shipped for real: TS7 is out, and `next build` uses it for type checking once you bump your local `typescript` dependency to `^7`.
- **ISR learned the shell trick.** Pages you don't prerender with `generateStaticParams` now serve an instant loading shell to their first visitor, then upgrade to the prerendered page in the background instead of blocking.
- **Offline resilience (experimental).** With `experimental.useOffline`, navigations and Server Actions that would throw on a dropped connection stay pending and retry on reconnect, plus a `useOffline` hook for showing a banner.
- **Stabilized names.** The `instant()` Playwright helper, `catchError`, `retry`, and `export const prefetch` all dropped their unstable prefixes for good.
- **One correction to the post below:** Vercel retired the first-party docs skills. The auto-managed `AGENTS.md` block does that job now, so don't go looking for them.
- **Sharp edges filed down.** The styled-jsx style leak from our sharp-edges list is fixed in stable, and the vendored lodash got a CVE patch.

**Our upgrade, preview.5 to stable:** the bump itself was one version change, but the monorepo bit us again, in a new place. Next.js 16.3 now includes `@types/node` in its peer fingerprint, and two of our apps pinned `^20` while the rest sat on `^24`. That split `next@16.3.0` into two type-graph instances, and `next.config.ts` exploded with the same baffling two-copies errors as last time. The fix was aligning `@types/node` across the workspace, not an override. If your typecheck breaks after the stable bump, check for a duplicate `next` first; it's always a duplicate `next`.

**Did stable get faster?** We benchmarked `next build` on this site (Apple Silicon, ~70 static routes, same machine, same content) before and after:

| Build | `16.3.0-preview.5` | `16.3.0` stable |
| --- | --- | --- |
| Cold (no cache) | 50.2s total / 9.6s compile | 50.4s total / 8.9s compile |
| Repeat build | ~50s (no build cache by default) | **23.6s total / 1.6s compile** |

| build | preview.5 (s) | 16.3.0 stable (s) |
| --- | --- | --- |
| Cold build | 50.2 | 50.4 |
| Repeat build | 50.2 | 23.6 |

*next build on this site, preview.5 vs 16.3.0 stable (seconds). Our measurements: apps/web, same machine, cold = .next wiped, repeat = second consecutive build*

Cold builds are flat, which is what we expected: our build time is mostly static generation and type checking, not compilation. The win is the now-default build cache, which took one settling build to warm up and then cut repeat compiles from 8.9s to 1.6s and total build time roughly in half. On CI that carries `.next/cache` between runs, that's the difference you'll actually feel. Runtime-wise there's nothing to measure on a fully static site; the 22% more requests under load from Node.js streams applies to apps that render per-request, not ours.

The verdict from the post below hasn't moved: `cacheComponents` and `partialPrefetching` are still opt-in, our adoption PR is still parked, and this site is still plain static files, just built faster.

> **This post was written against the preview.** Everything below comes from running `16.3.0-preview.5` in production on this site (preview.6 landed July 13), the three official posts ([instant navigations](https://nextjs.org/blog/next-16-3-instant-navigations), [AI improvements](https://nextjs.org/blog/next-16-3-ai-improvements), [Turbopack](https://nextjs.org/blog/next-16-3-turbopack)), and a dig through the preview release notes on GitHub. The edit note above covers what changed by the time 16.3 went stable; the original text stands as written.

We upgraded this site to the preview the week it dropped, built the full instant-navigations adoption on a branch, and merged none of it, because a fully static site already navigates instantly. The change that made this site feel faster was cutting **341KB** of gzipped JavaScript.

## What's new and shiny

The 16.3 line runs to six preview tags and 87 canaries as of mid July. We've put the biggest feature first.

### Instant navigations: stream, cache, or block

Click a link on a typical server-rendered site and three things happen: you click, the browser waits for the server, and the next page appears. The wait in the middle can be 100ms or a full second depending on latency and how much work the server does, and while it lasts the page doesn't move. That gap is why apps like Linear went client-heavy in the first place: an SPA puts *something* on screen immediately, then fills in the data.

16.3 keeps the server-driven model and goes after the wait. With the new flags on, every route has to answer one question: what can the user see immediately when they navigate here? Three answers count.

**Stream.** Wrap slow data in `<Suspense>`. The user gets the page shell with loading states straight away, and content streams in as the server finishes. This is the SPA feel.

**Cache.** Mark data fetches with `'use cache'`. The user gets previously cached UI, reused across requests, with no loading state at all.

**Block.** Some pages should wait. A blog post that flashes a skeleton for half a second is worse than a blank beat followed by the full article. Those routes opt out explicitly:

```tsx title="page.tsx"
export const instant = false;
```

The enforcement is the clever bit. In development, a navigation that can't respond instantly is now an **error**, surfaced in a new Instant Insights panel. You fix it by streaming or caching, or you declare the blocking deliberate. Slow navigations stop being something users find in production and become something the framework flags at dev time.

There's a Playwright helper to hold that line in CI:

```tsx
import { instant } from '@next/playwright';

await instant(page, async () => {
  await page.click('a[href="/products/hats"]');
  await expect(page.locator('h1')).toContainText('Baseball Cap');
});
```

Assertions inside the `instant()` block have to pass without any network roundtrip. Existing tests check whether a page works; this checks whether it responds before the server does.

### Partial prefetching: one shell per route

Until now, Next.js fired a prefetch request for every link in the viewport. A sidebar with twenty chat links meant twenty prefetch requests, all pointing at the same route. Vercel's own words: "Many of you told us that this looked ridiculous, and frankly, we agree."

16.3 prefetches one reusable shell per route instead: one for `/chat/[id]`, one for `/dashboard`, cached for the whole session. Click any of the twenty chat links and the shell renders immediately while that chat's data streams in. If a shell isn't enough (say you want the chat header to arrive with real content), you escalate per link:

```tsx
<Link href="/chat/42" prefetch={true}>
```

Even then, Next.js only prefetches down to what's synchronously available or marked `'use cache'`. Prefetching used to be all-or-nothing, which was the main reason to turn it off entirely; now there's a middle setting.

Both behaviors sit behind flags in `next.config.ts`, and both are planned defaults in a future major:

```typescript title="next.config.ts"
const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
};
```

The DevTools also grew a Navigation Inspector that pauses every navigation at the shell stage. It's the fastest way we found to see exactly what a user gets during that first paint.

### Turbopack stops holding everything in RAM

Dev memory eviction is now on by default: Turbopack moves cold compiler state out to the filesystem cache instead of holding everything in RAM. Vercel's own dashboard app dropped from 21.5GB to 2GB of dev-server memory, nextjs.org went from 4.6GB to 0.84GB, and a user in the [feedback thread](https://github.com/vercel/next.js/discussions/95130) reported 20GB down to 5GB.

| app | Before (GB) | With eviction (GB) |
| --- | --- | --- |
| vercel.com | 21.5 | 2 |
| nextjs.org | 4.6 | 0.84 |
| Community report | 20 | 5 |

*Turbopack dev-server memory, before and after eviction (GB). Source: Vercel's Turbopack post and discussion #95130*

Builds get the same treatment behind `experimental.turbopackFileSystemCacheForBuild`: the persistent cache that already speeds up dev now applies to `next build`, so CI can carry `.next` between runs. Vercel's numbers again:

| build | Cold (s) | Warm cache (s) |
| --- | --- | --- |
| nextjs.org | 21 | 9.2 |
| vercel.com/home | 66 | 46 |
| vercel.com/geist | 30 | 5.5 |

*next build times with the filesystem cache (seconds). Source: Vercel's Turbopack post*

Two smaller Turbopack items: an experimental Rust port of the React Compiler (`experimental.turbopackRustReactCompiler`, 20-50% faster compilation in their tests, Turbopack-only), and Vite-compatible `import.meta.glob` support, which matters if you're migrating from Vite or you load content files by pattern.

Every benchmark above is Vercel measuring Vercel's own apps, plus one community report. Nobody independent has reproduced them yet, which is normal three weeks into a preview, but treat them as directional.

### The framework now assumes an agent is in the loop

16.3 is the first release where the framework openly assumes an AI agent is part of the dev loop. `next dev` detects a coding agent and writes a managed block into your `AGENTS.md`, pointing the agent at version-matched docs bundled inside `node_modules/next/dist/docs`. The block keeps itself current across upgrades, and `agentRules: false` in the config turns it off. The docs went agent-readable too: append `.md` to any nextjs.org/docs URL and you get plain markdown. We shipped [the same markdown-twin pattern on this site](/blog) last year.

The repo now ships four first-party agent skills: one that adopts cache components for you, one that optimizes routes after adoption, one that adopts partial prefetching, and a dev-loop skill that connects your agent to the running dev server through a new `/_next/mcp` endpoint. That MCP server has a `compile_route` tool, so an agent can ask "does this route compile" in seconds instead of paying for a full `next build` to find out.

Dev errors got the same treatment. Every Instant Insights error carries a Copy prompt button that produces a ready-to-paste agent prompt, and the error docs pages are structured (patterns, trade-offs, gotchas) so an agent can act on them without a human translating. Having built our whole content pipeline around agents, we rate this as the sleeper feature of the release.

### Node streams by default, edge runtime deprecated

The "better rendering under stress" tease from the announcement doesn't have its own post yet, but the release notes show what it is: rendering moved off Web Streams onto native Node.js streams, on by default since canary 38. If your app serves heavy server-rendered pages under load, this is where that improvement lives.

Also in the release notes: **the edge runtime is deprecated** as of this line. We hit it from the other side, since adopting cache components on our branch forced our OG image route off the edge runtime and onto Node anyway. If you export `runtime = 'edge'` anywhere, start planning the move now rather than at the next major.

### Security patches now arrive monthly

Next.js security fixes used to ship whenever a fix was ready, which meant keeping up was a matter of watching the releases page. As of July 13 that's a schedule: one security release a month, with the first due July 20.

That first release patches 16.2 and 15.5. Two useful facts fall out of that. Stable 16.3 is still at least a few weeks away, and the 15.x line is still getting security fixes, so teams on the older major can upgrade on their own timetable. If you maintain a Next.js site, a monthly bump alongside the release cadence covers you, and it's a five-minute job now that the timing is predictable.

No help for us, mind. This site runs the 16.3 preview in production, which is exactly the sort of thing a security schedule exists to discourage, and we do it so we can write posts like this one. Every client project sits on patched stable, upgraded monthly, boring on purpose. Our own site takes the preview tags and finds out. If something in 16.3 was going to break a production deploy, we'd much rather it broke ours.

### The grab bag, explained simply

The rest of the release notes are smaller features whose one-line changelog entries assume you already know what they mean, so here's the plain-English version of each.

**Service workers, compiled properly.** A service worker is a small script the browser keeps around for your site even when no tab is open. It's what makes offline mode, push notifications, and "install this site as an app" work. Next.js never had first-class support, so PWA setups leaned on community plugins and files copied into `public/`. Turbopack now compiles service workers like any other entry point and serves them from `/_next/static`, in both App and Pages router.

**`next/root-params`.** If your app starts with a dynamic segment like `app/[lang]/`, every component that needed the language took it as a prop, threaded down layer by layer. Now it's `import { lang } from 'next/root-params'` and `await lang()` from any server component, no prop threading. The getters come from your actual folder names, so the API surface is literally your directory structure. New in 16.3, server components only for now.

**`'use cache: private'`.** Regular `'use cache'` output is shared between all visitors, which is exactly wrong for anything derived from cookies (a username in the header, a cart count). The `private` variant caches in that one visitor's browser instead, so personalized fragments can still take part in instant navigations without one user seeing another's data.

**`staleTimes`.** The router keeps in-memory copies of pages you've visited so going back is instant. `staleTimes` is the dial for how long those copies are trusted before refetching: `static` for fully prefetched pages (default 5 minutes) and `dynamic` for everything else (default 0, meaning always refetch). Still experimental, and it answers "why does clicking back sometimes refetch and sometimes not".

**Graph CSS chunking.** Bundlers have to decide how to split your CSS into files. Split too little and every page downloads all your styles; split per route and shared styles get duplicated or arrive in the wrong order, which is how you get the classic "this page looks different when I navigate to it versus when I refresh on it" bug. The new `experimental.cssChunking: "graph"` mode groups styles by which ones are actually used together across pages, instead of guessing from the route tree.

**`catchError` and `retry` lost their prefixes.** We flagged both in [the 16.2 post](/blog/nextjs-16-2-for-dummies) as `unstable_` experiments you shouldn't build on. In 16.3 the prefixes are gone: `catchError` handles server component errors without needing a whole `error.tsx` boundary, and `retry` inside an error boundary re-fetches the data rather than just clearing the error state and hoping.

**A faster TypeScript, experimentally.** Microsoft is rewriting the TypeScript compiler in Go (the project is called tsgo, and it typechecks roughly 10x faster). 16.3 adds an experimental flag to use it as the CLI's TypeScript backend. If your `next build` spends most of its time in typechecking, this is the line to watch.

### Feature status at a glance

| What | Status in the 16.3 preview |
| --- | --- |
| Instant navigations (stream / cache / block) | Opt-in via `cacheComponents: true` |
| Partial prefetching (one shell per route) | Opt-in via `partialPrefetching: true` |
| `instant()` Playwright test helper | New `@next/playwright` package |
| Turbopack dev memory eviction | On by default |
| Persistent cache for `next build` | `experimental.turbopackFileSystemCacheForBuild` |
| Rust React Compiler | Experimental, Turbopack-only |
| Native Node.js streams rendering | On by default |
| `AGENTS.md` auto-managed block | On when a coding agent is detected |
| Docs as markdown (`.md` suffix, llms.txt) | Live on nextjs.org |
| Monthly security releases | First one July 20, patching 16.2 and 15.5 |
| Edge runtime | Deprecated |

## Our upgrade experience

We bumped this site (a pnpm monorepo with three Next.js apps) to `16.3.0-preview.5` on June 30. The upgrade itself was uneventful: React 19.2.3 already satisfied the peer range, no code changes, production build green on the first try.

The one gotcha was monorepo-specific. A transitive peer dependency (a workflow package that peers on `next >13`) resolved its own copy of `next@16.2.1` alongside our preview version. Two copies of Next.js in one type graph means `check-types` explodes with baffling errors about incompatible internal types. The fix is a version-specific pnpm override in the root `package.json`:

```json title="package.json"
{
  "pnpm": {
    "overrides": {
      "next@16.2.1": "16.3.0-preview.5"
    }
  }
}
```

That collapses everything to one resolution. If you're in a monorepo and your typecheck breaks after the bump, check for a duplicate `next` before you blame the preview. Upgrade, override, green build: done in an afternoon.

Two weeks of running the preview in production since, and zero runtime issues. The risk in a preview is the APIs changing under you, not the code falling over, which is why the new flags stay off on this site until stable.

## The PR we didn't merge

We did the full adoption on a branch: `cacheComponents` and `partialPrefetching` on site-wide, the disallowed segment configs (`dynamic`, `revalidate`, `dynamicParams`) removed from every page and route handler, blog rendering wrapped in a `'use cache'` boundary, build-time non-determinism fixed (cache components forbids it), the OG image route moved off the edge runtime, plus a 19-test Playwright suite asserting instant navigation. Everything came back green.

Then we clicked around both deployments for a week and couldn't feel the difference.

The reason is boring: this site is already fully static. Every content page is prerendered at build time and served as files from a CDN. There's no server work for a loading shell to hide, so the navigation delay was never server-side. Cache components would have added a preview flag, a determinism constraint on the whole codebase, and soft-404 shell behavior we had to `noindex` around, in exchange for a difference we could not perceive with our own hands on the trackpad.

So the PR sits open, rebased and waiting for stable, and this site is still plain static files.

### Spin up every variant, then click around

The method is the takeaway here, more than the verdict. We didn't debate rendering strategy in a doc. We had three deployments up at the same time:

1. Full SSG (main, the control)
2. Cache components with partial prefetching
3. Cache components without partial prefetching

Then we navigated all three by hand, over an average office connection. We skipped the synthetic benchmarks because perceived navigation speed barely registers in metrics, and you can feel it within thirty seconds of using the site.

This used to be an expensive way to decide, a day or more of engineer time per variant. With coding agents it's close to free: describe the variant, let the agent build the branch, get a preview URL per PR. Two of our three PRs existed for a week purely so we could click around them and close them, and they settled an argument no benchmark could.

## What actually made the site feel faster

While we were testing rendering variants we found the real problem, and it wasn't rendering strategy. It was payload.

Our MDX component map registered every component as an eager client reference on every content page. A decorative WebGL particle effect on team member cards was shipping `three` and `@react-three/fiber` (roughly 400KB) to every blog post. Four chart components used by exactly one post were shipping `recharts` (about 110KB) to all of them. Syntax highlighting ran client-side too, so `react-refractor` and its language grammars rode along on every page.

The fix was dynamic imports with `ssr: false` behind `"use client"` wrappers, which moves the heavy leaves into on-demand chunks outside the page manifest. Syntax highlighting moved to the server entirely, since it renders static markup with no hooks; only a small copy-button island stays client-side. One subtlety worth knowing: `next/dynamic` inside the RSC renderer does not help here, because the client-reference manifest still bundles the component. The dynamic import has to live inside a client component.

The measured result on content pages, from the merged PR:

| Metric | Before | After | Change |
| --- | --- | --- | --- |
| Eager first-load (gzip) | ~1196KB | ~855KB | **-341KB (-29%)** |
| three + @react-three/fiber | Every content page | On demand | ~400KB deferred |
| recharts | Every content page | On demand | ~110KB deferred |
| Syntax highlighting | Client bundle | Server-rendered | Grammars never ship |
| SSG classification | 51 SSG / 20 static | 51 SSG / 20 static | Unchanged |

| state | kb |
| --- | --- |
| Before | 1196 |
| After dynamic imports | 855 |

*Content-page eager first-load, gzipped (KB). Source: our merged bundle-trim PR*

This is the change we could feel. Less JavaScript means the browser parses, compiles, and hydrates less before the page responds to input. The click-to-movement gap that instant navigations targets got shorter on our site because there was less code standing between the click and the movement.

Both fixes are real: instant navigations is the right one for server-time gaps, and a smaller bundle is the right one for client-time gaps. Check which one you actually have before reaching for either.

> **Next.js performance work**: Bundle audits, rendering strategy, and Core Web Vitals on real production sites. [See how we work with Next.js](/services/nextjs)

## Should you enable it?

Depends what you run.

**App-like sites (dashboards, feeds, anything personalized or data-heavy):** yes, this feature is for you. Your navigations do real server work, and a streaming shell is a much better answer than either blocking or client-fetching everything. Try the preview on a branch now, ship it at stable.

**Content sites that can go fully static:** you already have instant navigations. They're called static files. Spend the effort on your bundle instead; run a build analysis and find your equivalent of a 400KB particle effect. We'd bet money you have one.

**Everything in between:** the flags are opt-in per project but the *discipline* is per route. Enabling them forces every route to declare stream, cache, or block, which is a useful audit even if you end up blocking half your routes.

## Quick comparison

| | Next.js 16.2 | Next.js 16.3 (preview) |
| --- | --- | --- |
| Link prefetching | Every link in the viewport | One reusable shell per route (opt-in) |
| Slow navigations | Users find them in production | Dev-time errors in Instant Insights |
| Turbopack dev memory | Compiler state held in RAM | Cold state evicted to disk by default |
| Persistent Turbopack cache | Dev only | `next build` too (experimental) |
| Rendering | Web Streams | Native Node.js streams |
| React Compiler | JavaScript implementation | Experimental Rust port (Turbopack-only) |
| `catchError` / `retry` | `unstable_` prefixed | Stable |
| Agent tooling | `AGENTS.md` by hand | Managed block, four skills, `/_next/mcp` |
| Edge runtime | Available | Deprecated |
| Security releases | Whenever a fix was ready | Monthly, from July 20 |

## How to upgrade

Three routes, depending on how much you want to adopt today.

**Option 1: bump the version, leave the flags off.** This is what we run in production:

```bash
npm install next@preview
```

For most apps that's the whole job. Ours needed the pnpm override above, and yours might need its equivalent if you're in a monorepo.

**Option 2: let an agent do the adoption.** Vercel published an [agent skill for adopting cache components](https://github.com/vercel/next.js/tree/canary/skills/next-cache-components-adoption), and the migration is mostly mechanical: remove segment configs, add cache boundaries, fix determinism. It's a sensible thing to delegate, and it's how we'd redo our branch when stable lands.

**Option 3: wait for stable.** There's no date yet, and the July 20 security release targets 16.2 and 15.5, so stable 16.3 is at least a few weeks out. Waiting costs you nothing except time with the Instant Insights panel; the flags will still be opt-in when it lands.

If you do flip the flags, expect errors on day one. Each one is a route that's slow today without anyone having noticed, which is exactly what you flipped the flags to find out. The [preview docs for instant navigations](https://preview.nextjs.org/docs/app/guides/instant-navigation) cover the details.

### Current sharp edges

The [feedback thread](https://github.com/vercel/next.js/discussions/95130) is the live list of what breaks right now. Worth knowing before you flip the flags:

- **Static exports don't work with partial prefetching.** If you ship `output: 'export'`, this whole feature set isn't for you yet.
- **Instant Insights false-flags parallel routes** that never actually render, so you may get errors about slots you can't fix. Under review.
- **Global styled-jsx styles can leak between routes** when UI state is preserved across a navigation. Scope your overrides.
- **`turbopackIgnore` comments don't silence dynamic `path.join()` file access**, which can trace entire directories into your standalone output and balloon deploy size. A fix is in flight.
- **Self-hosting on SST** (v4.17+) with `cacheComponents` can break SSR entirely; the current workaround is turning the flag off. Vercel and AWS/OpenNext deploys are reported working.
- **Safari's dev tooling is flaky** for Instant Insights; use Chrome or Firefox during development.

Two bugs you might have read about are already fixed in later canaries: the page title rendering as a URL path after navigation, and Windows access-denied errors on the Turbopack cache. Both fixes should be in the next preview tag if they aren't in yours.

## Closing thoughts

Stable 16.3 has no date, the first monthly security release lands July 20, and our cache-components branch stays parked until there's a stable tag to rebase onto. We'll do the full writeup when that happens, including whether the parked PR finally merges.

## Frequently asked questions

### What are instant navigations in Next.js 16.3?

A set of opt-in behaviors that make link clicks respond immediately, like a single-page app. Every route either streams a loading shell with Suspense, serves cached UI via 'use cache', or explicitly opts out with export const instant = false. Slow navigations become errors in development so regressions get caught before users feel them.

### Is Next.js 16.3 stable now?

Yes. 16.3.0 went stable on August 3, 2026, and npm install next@latest gets you everything in it. We ran 16.3.0-preview.5 in production on this site from June 30 with zero runtime issues, and moved to stable 16.3.0 the week it landed. The cacheComponents and partialPrefetching flags are still opt-in even on stable.

### Do instant navigations require cache components?

Yes. Both new behaviors sit behind cacheComponents: true, and the new prefetching additionally needs partialPrefetching: true in next.config. Both flags are planned defaults in a future major version, so adopting them now is early but not a dead end.

### Does a fully static SSG site need instant navigations?

Mostly no. If every page is prerendered, there is no server work to hide behind a loading shell, and navigations are already served from static files. We built the full adoption for our own SSG site and could not feel the difference, which is why we did not merge it. Sites with real per-request work (dashboards, feeds, anything personalized) are where it pays off.

### What is partial prefetching in Next.js?

Instead of firing a prefetch request for every link in the viewport, Next.js prefetches one reusable shell per route and caches it for the session. Twenty chat links to /chat/[id] used to mean twenty prefetch requests; now it is one. Per-link prefetching is still available by opting in with <Link prefetch={true}>.

### How do you make a Next.js site feel faster without cache components?

Ship less JavaScript. We cut our content-page first load from roughly 1196KB to 855KB gzipped (29% less) by moving three.js, recharts, and interactive widgets behind dynamic imports with ssr: false, and rendering syntax highlighting on the server. That one PR did more for perceived speed than any rendering flag we tested.

### How hard is upgrading to Next.js 16.3?

One command for most apps: npm install next@latest. Our monorepo needed extra steps both times, because two copies of Next.js in one type graph make typechecking explode. The preview upgrade needed a pnpm override to collapse a duplicate a transitive peer dependency pinned; the stable upgrade needed @types/node aligned across workspace apps, because Next.js 16.3 includes it in its peer fingerprint. Upgrade, dedupe, green build.

### What does export const instant = false do?

It marks a route as intentionally server-bound. Development treats slow navigations as errors under the new flags; if you want a route to wait for the server rather than show a loading shell (a blog post, for instance), instant = false tells Next.js the blocking behavior is deliberate and silences the error.

### What else is new in Next.js 16.3 besides instant navigations?

Turbopack dev memory eviction (Vercel's dashboard went from 21.5GB to 2GB of dev-server RAM), an experimental persistent cache for next build, an experimental Rust port of the React Compiler, rendering moved to native Node.js streams by default, Vite-compatible import.meta.glob, first-class service worker compilation, auto-managed AGENTS.md blocks for coding agents, four first-party agent skills, and a deprecated edge runtime.

### Is the Next.js edge runtime deprecated?

Yes, as of the 16.3 line. Routes exporting runtime = 'edge' should plan a move to the Node runtime. We hit this ourselves: adopting cache components forced our OG image route off the edge runtime, so the two changes push in the same direction.

### What is 'use cache: private' in Next.js?

A variant of 'use cache' for data derived from cookies or headers. Regular 'use cache' output is shared between all visitors; the private variant caches in that one visitor's browser instead, so personalized fragments (a username, a cart count) can join instant navigations without leaking between users.

## Related posts

- [Optimized data fetching in Next.js 15](/blog/optimized-data-fetching-in-nextjs-15)
- [React Server Components CVE-2026-23864: What you need to know](/blog/react-server-components-cve-2026-23864-what-you-need-to-know)
- [Build it right once](/blog/build-it-right-once)