NextJS Link Prefetching

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

NextJS Link Prefetching

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Link Prefetching

The Link component provided by NextJS does automatic prefetching of its destination. Prefetching is only done in production (you can build with next build).

This is demonstrated in the below example where alpha and beta routes are prefetched and we can verify it from the browser developer tools.

app/page.tsx
import Link from "next/link";

export default function Home() {
return (
<div>
<Link href="/alpha">Go to Alpha</Link>
<Link href="/beta">Go to Beta</Link>
</div>
);
}

Only on Viewport

Only the Link components in the viewport are fetched.

This is demonstrated in the below example where prefetching is only observed as you scroll through the links.

app/page.tsx
import Link from "next/link";

export default function Home() {
return [...Array(500)].map((_, i) => (
<div key={i}>
<Link href={`/example/${i + 1}`}>Example {i + 1}</Link>
</div>
));
}

Disable Prefetching

You can disable prefetching for a Link component quite easily by passing in the prop prefetch={false}.

Prefetch Options

The prefetch prop actually defaults to null.

The difference between the options (true | false | null) is:

  • false: Prefetching will never happen.
  • true: The full route will be prefetched for both static and dynamic routes.
  • null (default): For static routes, the full route will be prefetched (including all its data). For dynamic routes, the partial route down to the nearest segment with a loading.js boundary will be prefetched. This still gives the user an immediate navigation experience. However, the final route itself is not prefetched to conserve server resources. The final route is only fetched if the user navigates to the link.

This is demonstrated in the below example:

app/page.tsx
app/value/false/page.tsx
app/value/true/page.tsx
app/value/null/page.tsx
app/static/page.tsx
app/dynamic/loading.tsx
app/dynamic/page.tsx
import Link from "next/link";

export default function Home() {
return (
<div>
<Link href="/value/false">false</Link>
<Link href="/value/true">true</Link>
<Link href="/value/null">null</Link>
</div>
)
}
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

As you've mentioned a few times, next J is hyper-focused on providing the best user experience out of the box link. Prefetching is just another example of this principle to demonstrate. We have an application that has a simple homepage that links to the pages alpha and beta. If you look at this application within the browser, nothing special is happening. Over here. We have simple links to Alpha and beta. Prefetching only works in production as it would make for a very confusing developer experience during development with components rendering, even though they are not on screen. So we open up the terminal

00:31

and run a production build of our application and then start that built production app. So let's take a look at this production built application with the developer tools open. You can see that when this page runs two additional fetch calls are made to the alpha and the beta routes. These calls to Prefetch alpha and beta are actually being made by the link component provided by next js. As you would imagine, we wouldn't want to prefetch every link on the page as it would be pretty wasteful. So next year is smart enough to only prefetch as the links come into view,

01:04

because the links in the viewport are the links that the user is likely to visit. To demonstrate this, we have another application that renders out 500 links as a part of its homepage. If you build this application and then take a look at what it looks like within the browser, you can see that we have a number of links being displayed on screen, but additionally, a number of prefetch requests have been made to different routes. Now, there are actually 500 links on this page, but only 27 requests have been made until now. As we scroll through the page,

01:36

different links come into view, and therefore prefetch requests are made for these links that are entering within the viewport. The results of these prefetch requests are actually put into the router cache within next years. Now, of course, we don't want it catching the output indefinitely and hogging up the computer memory, so it does have a default timeout of five minutes. If you are displaying a lot of links in a loop, for example, in a grid or a table or in a list the way we have done, then it makes sense to completely disable prefetching for these links. This is because the user is only likely to visit one

02:09

of these links, so it isn't efficient to pre-render so many links that the user will never even visit. Fortunately, disabling prefetching for a link is quite easy. We simply set the prefetch prop to be false. So with this value set, we rebuild our application and then let's take a look at it within the browser. Hey, you can see that within the network tab, there are no more prefetch requests being made by the link component. It's great for the browser as it's not hogging system resources with this cache, and it's great for the server as it isn't rendering pages

02:41

that the user might never even visit. In addition to bullion values, the link component Prefetch prop also accepts null and null is actually the default if you do not provide a value. So let's discuss the prefetch behavior difference between two false and now to truly demonstrate the difference between These these options, we need at least three pages, a static page, a dynamic page, and a loading screen for the dynamic page. We already have a dedicated lesson on static versus dynamic rendering. So as you would imagine, aesthetic page is quite easy. A dynamic page is dynamic

03:15

because of export cons, dynamic first dynamic. Additionally, we take some time to render this page by using a wait on a promise that is resolved with a set timeout after three seconds and during the time that this component is still being rendered. Next J, we'll automatically render the learning component as a placeholder. As we discussed in our routing core concepts Lesson. Before we continue, it is worth pointing out that we already know that the static page is going to get pre rendered as a part of our next build with this three page infrastructure in place. Let's take a look at the difference

03:47

of using the prefetch values of false true and now. Now, we've already looked at false before and there is actually no difference between static and dynamic pages when it comes to false. Basically false completely disables link prefetching, and therefore we do not see any fetch requests within the network tab. The exact opposite of false is true way true will always do link prefetching. Doesn't matter if the page is static or dynamic, the behavior will be the same. All route files related to that page will be pre fetched when the value is set to true. What this means for dynamic pages is that in addition

04:21

to the loading page, the final page is also pre fetched. Finally, we have the default value, which is now, now behaves the same as true for static pages, but for dynamic pages, it only pre fetches the loading page, but does not render the final page as it might consume more resources to truly appreciate the difference between two and null. Let's do a practical demonstration of the user experience between these two values. The experience between two and null for static pages will be the same. The static pages will get prefetch all the way through.

04:54

The difference in the user experience is only for dynamic pages with the value set to two. Even dynamic pages are pre fetched all the way through, and we can see this because the dynamic page is loaded immediately, even though we know it actually takes three seconds to render. And the reason is that it was pre fetched by the link component with the default value of prefetch. Now, the experience for dynamic pages is going to be different with Prefetch value sentinel, everything regarding the dynamic page will be fetched except the dynamic page itself.

05:26

This means the common layout will be fetched. The loading component will be pre fetched, but the dynamic page itself will not be pre fetched to conserve server resources. So we still get an immediate navigation experience because after all, the loading route was pre fetched. However, once that is there, the dynamic page starts rendering, and once it is complete, that loading is replaced by the final page.