How Next.js speeds up navigations with route prefetching and how to customize it.


![Milica Mihajlija](https://web.dev/images/authors/mihajlija.jpg) Milica Mihajlija [X](https://twitter.com/bibydigital) [GitHub](https://github.com/mihajlija) [Homepage](https://mihajlija.github.io/)

<br />

In this post, you learn how routing in Next.js works, how it's optimized for speed, and how to customize it to best fit your needs.

> [!CAUTION]
> **Caution:** This page has one or more broken demos, as [Glitch has ended hosting](https://blog.glitch.com/post/changes-are-coming-to-glitch).

## The `<Link>` component

In [Next.js](https://nextjs.org/), you don't need to set up routing manually.
Next.js uses file-system-based routing, which lets you just create files and folders
inside the `./pages/` directory:

![Pages directory that contains three files: index.js, margherita.js, and pineapple-pizza.js.](https://web.dev/static/articles/route-prefetching-in-nextjs/image/screenshot-the-pages-dir-81addfb477754.png)

To link to different pages, use the
[`<Link>`](https://nextjs.org/docs/api-reference/next/link) component, similarly to how you'd
use the good old `<a>` element:

    <Link href="/margherita">
      <a>Margherita</a>
    </Link>

When you use the `<Link>` component for navigation, Next.js does a little bit
more for you. Normally, a page is downloaded when you follow a link to it, but
Next.js automatically prefetches the JavaScript needed to render the page.

When you load a page with a few links, odds are that by the time you follow
a link, the component behind it has already been fetched. This improves
application responsiveness by making navigations to new pages quicker.

In the example app the `index.js` page links to `margherita.js` with a
`<Link>`:
<iframe allow="camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi" loading="lazy" src="https://glitch.com/embed/#!/embed/nextjs-prefetching?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=pages%2Findex.js&amp;previewSize=100" style="height: 100%; width: 100%; border: 0;" title="nextjs-prefetching on Glitch"></iframe>

Use Chrome DevTools to verify that `margherita.js` is prefetched:
1. To preview the site, press **View App** . Then press
**Fullscreen**
![fullscreen](https://web.dev/static/images/glitch/fullscreen.svg).

1. [Open Chrome DevTools](https://developer.chrome.com/docs/devtools/open).
2. Click the **Network** tab.
3. Select the **Disable cache** checkbox.
4. Reload the page.

When you load `index.js`, the **Network** tab shows that `margherita.js` is
downloaded too:

![DevTools Network tab with margherita.js highlighted.](https://web.dev/static/articles/route-prefetching-in-nextjs/image/devtools-network-tab-mar-ff03141455652.png)

## How automatic prefetching works

Next.js prefetches only links that appear in the viewport and uses the [Intersection
Observer API](https://developer.mozilla.org/docs/Web/API/Intersection_Observer_API)
to detect them. It also disables prefetching when the network connection is slow
or when users have
[`Save-Data`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Save-Data)
turned on. Based on these checks, Next.js dynamically injects [`<link
rel="preload">`](https://web.dev/articles/preload-critical-assets) tags to download components for
subsequent navigations.

Next.js only *fetches* the JavaScript; it doesn't execute it. That way, it's not
downloading any additional content that the prefetched page might request until you visit
the link.

> [!CAUTION]
> **Caution:** Glitch examples are running in production mode because prefetching depends on the browsing conditions and it's enabled only in optimized production builds. To switch to development mode, check the `README.md` in Glitch examples.

> [!NOTE]
> **Note:** Because `<link rel="preload">` requests resources with high priority, the browser expects them to be used right away, which triggers Console warnings. [Fetch Priority](https://web.dev/articles/fetch-priority) will is available in Chrome, which will allow Next.js to indicate lower priority for resources that are not needed immediately with `<link rel="preload" fetchpriority="low">`.

## Avoid unnecessary prefetching

To avoid downloading unnecessary content, you can disable prefetching for rarely
visited pages by setting the `prefetch` property on `<Link>` to `false`:

    <Link href="/pineapple-pizza" prefetch={false}>
      <a>Pineapple pizza</a>
    </Link>

In this second example app, the `index.js` page has a `<Link>` to
`pineapple-pizza.js` with `prefetch` set to `false`:
<iframe allow="camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi" loading="lazy" src="https://glitch.com/embed/#!/embed/nextjs-noprefetch?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=pages%2Findex.js%3A12%3A50&amp;previewSize=100" style="height: 100%; width: 100%; border: 0;" title="nextjs-noprefetch on Glitch"></iframe>

To inspect the network activity, follow the steps from the first example. When
you load `index.js`, the DevTools **Network** tab shows that `margherita.js` is
downloaded, but `pineapple-pizza.js` is not:

![DevTools Network tab with margherita.js highlighted.](https://web.dev/static/articles/route-prefetching-in-nextjs/image/devtools-network-tab-mar-6cc6381202dec.png)

## Prefetch with custom routing

The `<Link>` component is suitable for most use cases, but you can also build
your own component to do routing. Next.js makes this easier for you with the
router API available in [`next/router`](https://nextjs.org/docs/api-reference/next/router#userouter).
If you want to do something (for example, submit a form) before navigating to a new
route, you can define that in your custom routing code.

When you use custom components for routing, you can add prefetching to them too.
To implement prefetching in your routing code, use the `prefetch` method from
`useRouter`.

Take a look at `components/MyLink.js` in this example app:
<iframe allow="camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi" loading="lazy" src="https://glitch.com/embed/#!/embed/custom-routing-nextjs?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=components%2FMyLink.js&amp;previewSize=100" style="height: 100%; width: 100%; border: 0;" title="custom-routing-nextjs on Glitch"></iframe>

Prefetching is done inside the
[`useEffect`](https://reactjs.org/docs/hooks-effect.html) hook. If the
`prefetch` property on a `<MyLink>` is set to `true`, the route specified in the
`href` property gets prefetched when that `<MyLink>` is rendered:

    useEffect(() => {
        if (prefetch) router.prefetch(href)
    });

When you click the link, the routing is done in `handleClick`. A message gets
logged to the console, and the `push` method navigates to the new route
specified in `href`:

    const handleClick = e => {
        e.preventDefault();
        console.log("Having fun with Next.js.");
        router.push(href);
    };

In this example app, the `index.js` page has a `<MyLink>` to `margherita.js` and
`pineapple-pizza.js`. The `prefetch` property is set to `true` on `/margherita`
and to `false` on `/pineapple-pizza`.

    <MyLink href="/margherita" title="Margherita" prefetch={true} />
    <MyLink href="/pineapple-pizza"  title="Pineapple pizza" prefetch={false} />

When you load `index.js`, the **Network** tab shows that `margherita.js` is
downloaded and `pineapple-pizza.js` is not:

![DevTools Network tab with margherita.js highlighted.](https://web.dev/static/articles/route-prefetching-in-nextjs/image/devtools-network-tab-mar-0199e278ff707.png)

When you click either link, the **Console** logs "Having fun with Next.js."
and navigates to the new route:

![DevTools Console displaying the message 'Having fun with Next.js.'](https://web.dev/static/articles/route-prefetching-in-nextjs/image/devtools-console-displayi-1ef8ccadbb2d2.png)

## Conclusion

When you use `<Link>`, Next.js automatically prefetches the JavaScript needed to
render the linked page, which makes navigating to new pages faster. If you are
using custom routing, you can use the Next.js router API to implement
prefetching yourself. Avoid downloading content unnecessarily by disabling
prefetching for rarely visited pages.