---
title: "Next.js 16.3: Instant Navigations"
description: A new suite of tools that brings the responsiveness of a single-page app to the server-centric model of Next.js.
url: "https://nextjs.org/blog/next-16-3-instant-navigations"
docs_index: /docs/llms.txt
publishedAt: June 24th 2026
authors:
  - Andrew Clark
  - Josh Story
---



<div className="not-prose my-8 space-y-4 rounded-lg border border-amber-400 bg-amber-100 p-4 text-copy-16 text-gray-1000 md:p-6">
  <div className="text-copy-18 font-semibold">
    Next.js 16.3 Preview is ready for public testing!
  </div>
  <div>
    We've published a new Next.js release to npm using the `@preview` tag, so
    you can try out 16.3 starting today. We expect to ship a polished stable
    release in the coming weeks.
  </div>
  <div>
    We'd love to hear any feedback you have about the preview [on
    GitHub](https://github.com/vercel/next.js/discussions/95130).
  </div>
</div>

Next.js 16.3 is almost here, and it's packed with a ton of improvements: better rendering under stress thanks to native Node.js streams, faster startup times in local dev, and deeper integration with agent-based workflows.

We'll be covering these features in the coming weeks as we prepare a stable release. But today, we'd like to focus on one new feature we're calling _Instant Navigations_ — a suite of tools that bring the responsiveness of client-driven SPAs to Next.js, without sacrificing the benefits that come with its server-driven model.

Let's see how this feature addresses the long-standing (and valid!) criticism that Server Components can make apps feel unresponsive.

## Instant Navigations

One of the most common frustrations we hear about Next.js apps is that navigations feel slow.

In a server-driven app, navigating usually requires a network roundtrip:

1. You click a link.
2. Nothing happens.
3. Then the server responds, and the next page appears.

This is not necessarily bad, and it can work well for content-driven websites like newspapers and blogs. But it does make the experience "feel like a website". It's not snappy. Compare this to how client-driven apps do navigations:

1. You click a link.
2. _Instantly,_ you see a shell of the next page (with some data still loading).
3. Then the server responds, and the next page fully reveals.

This is a common reason why many developers prefer to create SPAs (single-page apps). Even though the server-driven request/response paradigm has many advantages, instant navigations still _feel better_ for many kinds of apps.

### We're fixing this

We've heard your feedback about this loud and clear.

In Next.js 16.3, we are shipping new opt-in behaviors that let you have the best of both worlds: server-driven apps with instant navigations. **You get the full benefits of a server, but navigations are instant like in a single-page app.**

Let's have a look at how this works.

### First, enable Cache Components

To try these new behaviors, enable the Cache Components flag:

```js {4} filename="next.config.ts"
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  cacheComponents: true,
  // ...
};

export default nextConfig;
```

Over the last year, we've been simplifying Next.js back to its roots: dynamic by default, with no hidden or implicit caching. This flag enables those new behaviors, and it will become a default in a future major version of Next.js.

### Stream, Cache, or Block

Now, when a route `await`s some data on the server, you will be presented with a choice between a few options:

<figure>
  <Image
    srcLight="/static/blog/next-16-3-instant-navigations/insights-light-v3.png"
    srcDark="/static/blog/next-16-3-instant-navigations/insights-dark-v3.png"
    width={2160}
    height={1680}
  />
  <figcaption>
    The new Instant Insights panel automatically surfaces slow navigations
  </figcaption>
</figure>

What do these options mean?

To make a navigation instant, you "turn" an asynchronous operation into something that can be available instantly:

- [**Stream** with `<Suspense>`.](/blog/our-journey-with-caching#dynamic) The user will instantly see a loading state (with more UI streaming in after).
- [**Cache** with `'use cache'`](/blog/our-journey-with-caching#cached-functions). The user will instantly see a previously cached UI (reused between requests).

**In both cases above, the navigation will feel SPA-like and instant to the user.**

However, sometimes you might want to make a certain navigation server-bound. For example, a blog might choose to never show a loading shell for posts. For those cases, you can tell Next.js that you _want_ this navigation to **Block**:

```js
// in page.tsx or layout.jsx
export const instant = false;
```

Then the error dialog will go away.

Notice how this puts you in control. If you want your server-driven app to react to link clicks instantly—without waiting for the network—then you Stream or Cache. If you want some routes to delay navigations, then you Block.

<div className="not-prose my-8 rounded-2xl border border-green-700/30 bg-green-100 p-4 text-copy-16 text-gray-1000 md:p-6">
  <div className='text-green-900 uppercase text-sm font-semibold tracking-wide inline-flex items-start gap-2'>
    <svg
      viewBox="0 0 16 16"
      height="16"
      width="16"
      data-slot="geist-icon"
      style={{ color: 'currentcolor' }}
    >
      <path
        fill="currentColor"
        fillRule="evenodd"
        d="M8.75 2.8a1.5 1.5 0 1 0-1.5 0V5H7a6 6 0 0 0-5.92 5H0v3h1v3h14v-3h1v-3h-1.08A6 6 0 0 0 9 5h-.25zM7 6.5A4.5 4.5 0 0 0 2.5 11v3.5h11V11A4.5 4.5 0 0 0 9 6.5zm.25 4.75a1.75 1.75 0 1 1-3.5 0 1.75 1.75 0 0 1 3.5 0M10.5 13a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5"
        clipRule="evenodd"
      ></path>
    </svg>
    Agent skill
  </div>

<div className="mt-4">
  If you're looking to adopt Cache Components for the first time in an existing
  app, we've put together a Skill you can use to have your agent walk you
  through the process.
</div>

  <div className="mt-6">
    <CopyButton
      idle={<><IconCopyPrompt /> Copy prompt</>}
      success={<><IconCopyPrompt /> Copied!</>}
      value='Install this skill https://github.com/vercel/next.js/tree/canary/skills/next-cache-components-adoption and adopt Cache Components in this project using it'
      className="bg-gray-1000 text-background-100 px-4 py-2 rounded-full inline-flex text-sm font-medium items-center gap-2 hover:bg-gray-900 active:bg-gray-1000 focus-visible:outline-none focus-visible:shadow-[var(--ds-focus-ring)]" />
  </div>
</div>

### Keeping navigations instant

With Instant Insights, we've made slow navigations an error in development. To more easily catch regressions to your instant routes after changes and refactorings, we have also provided an `instant` test helper for Playwright tests:

```js {7-12}
import { expect, test } from '@playwright/test';
import { instant } from '@next/playwright';

test('product title is available immediately', async ({ page }) => {
  await page.goto('/products/shoes');

  // Assert what's visible without waiting for network
  await instant(page, async () => {
    await page.click('a[href="/products/hats"]');
    await expect(page.locator('h1')).toContainText('Baseball Cap');
    await expect(page.getByText('Checking inventory...')).toBeVisible();
  });

  await expect(page.getByText('12 in stock')).toBeVisible();
});
```

This lets you (or your agent) assert more granularly what must be instantly visible after each link click.

We're also exploring ways to surface the errors you see in development during the build process, so any regressions in your instant routes would be caught at build time.

### Rethinking prefetching

For navigations to feel truly instant (like SPAs), we've needed to close two different gaps:

- The client needs to talk to the server. This can be slow if there's high latency between them.
- Also, the server needs to generate a response. This can be slow if the server code is slow.

By Streaming or Caching the response, we get rid of the second gap: the server itself doesn't block. But there's still a gap _between_ the client and the server. How could Next.js "know" the response instantly _by the time the user clicks_?

Previously, Next.js solved this by sending a prefetch request to the server for every link in the viewport. If you paid attention to the Network tab in the production mode, you might have noticed a flurry of requests on scroll:

<figure>
  <div style={{ aspectRatio: '1280 / 720' }}>
    <Image
      srcLight="/static/blog/next-16-3-instant-navigations/prefetch-before-light-v2.png"
      srcDark="/static/blog/next-16-3-instant-navigations/prefetch-before-dark-v2.png"
      width={1280}
      height={720}
    />
  </div>
  <figcaption>
    In 16.2, Next.js makes a prefetch request for every link, even if those
    links point to the same route
  </figcaption>
</figure>

Many of you told us that this looked ridiculous, and frankly, we agree.

We've been thinking about how single-page apps solve this. A single-page app is able to respond to each navigation instantly because it bundles all the code that's necessary to display the next page and ships it to the client. It might still need more data—so clicking doesn't display a complete page—but it's enough to display a "shell" of the page.

So we've decided to borrow this trick from single-page apps. **Instead of prefetching a page _per link_, Next.js will now prefetch a reusable shell _per route_.** Those shells will then be cached on the client so they're only fetched once.

For example, if you had a sidebar with twenty chat links, Next.js used to send a separate prefetch request per link. However, with the new behavior, it will only prefetch once _per route_: a shell for the `/chat/[id]` route, a shell for the `/dashboard` route, and so on. Conceptually this is similar to how single-page apps download code with per-route code splitting.

<figure>
  <div style={{ aspectRatio: '1280 / 720' }}>
    <Image
      srcLight="/static/blog/next-16-3-instant-navigations/prefetch-after-light-v3.png"
      srcDark="/static/blog/next-16-3-instant-navigations/prefetch-after-dark-v3.png"
      width={1280}
      height={720}
    />
  </div>
  <figcaption>
    In 16.3, Next.js prefetches a single loading shell per route, and reuses it
    across links
  </figcaption>
</figure>

Because shells are reused across links, they're also a foundation for offline navigation. In a future release, we'll be exploring how prefetched routes could remain navigable when the network briefly disappears.

### Enabling Partial Prefetching

To try this new prefetching behavior, which we call Partial Prefetching, enable in your Next.js config:

```js {5} filename="next.config.ts"
import type { NextConfig } from 'next';

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

export default nextConfig;
```

Like with `cacheComponents`, we plan to make `partialPrefetching` the default behavior in a future major release.

### Inspecting the loading shell

To make this more visual, we've added a new Navigation Inspector to the Next.js DevTools.

It lets you pause every navigation _at the shell_ so that you can see what gets prefetched for any route:

<Image
  srcLight="/static/blog/next-16-3-instant-navigations/inspector-light.png?"
  srcDark="/static/blog/next-16-3-instant-navigations/inspector-dark.png?"
  width={2560}
  height={2048}
/>

Then, when you click "Resume", the navigation will show the completed page. This lets you see during development which part of your route can be displayed instantly, and which can only be displayed after the network hop.

Like before, actual prefetching is only enabled in production.

### Prefetching more than a shell

With Partial Prefetching on, we've reduced what Next.js prefetches by default.

Instead of firing off a prefetch request for every link, Next.js will now only prefetch a reusable shell per each distinct route in the viewport (one for Chat page, one for Settings page, and so on), and cache them throughout the session.

However, sometimes, you want to prefetch _more_ than the shell. For example, you might want a chat header to "pop in" instantly on a Chat page. To opt into per-link prefetching, you can add `<Link prefetch={true}>` to some links.

Note that even in that case, Next.js will not attempt to render the entire route all the way deep. Instead, it will render down to what's available synchronously or marked with `'use cache'`. This means that you no longer have to make an "all or nothing" choice with prefetching. The instant shell gives you the baseline, and then `<Link prefetch={true}>` with `'use cache'` lets you add additional per-link prefetching that may include more content.

To keep the costs conservative, per-link prefetching is limited to the content known at build time. If you don't mind extra server load, `export const prefetch = 'allow-runtime'` extends it to request-time cached content.

### We've been using it ourselves

We've been adopting these tools on [v0](https://v0.app) ahead of this release. v0 has lots of rich client features, but navigations had been falling short of feeling instant for a while.

Instant Insights pointed us at the routes that weren't navigating instantly. Here's how navigations got faster once we started working through the fixes:

<figure className="my-8">
  <Image
    srcLight="/static/blog/next-16-3-instant-navigations/v0-light.png"
    srcDark="/static/blog/next-16-3-instant-navigations/v0-dark.png"
    width={1868}
    height={712}
  />
  <figcaption>Navigation times in v0 (from click to route change)</figcaption>
</figure>

We'll share the specific patterns we landed on in a follow-up post. We're also still optimizing the prefetching improvements described earlier, so we expect these numbers to get closer to zero.

### Recap

To sum up, we've been working to let your app have Instant Navigations similar to a SPA:

- If you Stream with `<Suspense>` or Cache with `'use cache'`, navigations to your route will be instant.
- If you Block by `export const instant = false`, you opt out of enforcing instant navigations to that route.
- Next.js automatically generates a reusable shell for every instant route, and only prefetches it once.
- You can use the `instant()` test helper to avoid regressions, and Navigation Inspector to visually inspect shells.
- You can opt into a deeper per-link prefetching with `<Link prefetch>` and `'use cache'`.

These changes are gated behind `cacheComponents: true` and `partialPrefetching: true` flags.

With these changes, we are making the Next.js first-click navigation experience just as good as in single-page apps, but without giving up the benefits of the server-centric mental model and the overall performance that it allows.

## Try it today

To try out Instant Navigations for yourself, install the 16.3 Preview today:

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

Check out [the preview docs for Instant Navigations](https://preview.nextjs.org/docs/app/guides/instant-navigation) for more information.

<div className="not-prose my-8 space-y-4 rounded-lg border border-amber-400 bg-amber-100 p-4 text-copy-16 text-gray-1000 md:p-6">
  <div>
    **This is a pre-production release.** Although our own apps are using it,
    use discretion before deploying to real users. Changes are likely before the
    final stable release.
  </div>
</div>

We'd love to hear any feedback you have [on GitHub](https://github.com/vercel/next.js/discussions/95130), and we'll continue to publish updates to the `preview` tag as we work towards a polished stable release.

### Known issues

There are known issues in Preview that we're actively working on. These will be fixed prior to our stable release.

- **There are some cases where a blocking route won't get reported as an Instant Insight.** When Partial Prefetching is enabled, accessing params inside of a shell will cause a route to block, but this won't be reported as an Instant Insight. The Navigation Inspector and `instant()` test helper are unaffected.

- **There are some issues with the Instant Insights tooling in Safari.** In development, use Chrome or Firefox for best results.

Check back here to see when these issues get resolved.

## Feedback and community

Share your feedback and help shape the future of Next.js:

- [GitHub Discussions](https://github.com/vercel/next.js/discussions)
- [GitHub Issues](https://github.com/vercel/next.js/issues)
- [Discord Community](https://nextjs.org/discord)
