Modern Creator
Ankita Kulkarni · YouTube

Next.js 16.3 Finally Fixed Slow Navigations

How Cache Components and a new stream-cache-or-block mental model bring SPA-speed clicks back to the server-rendered App Router.

Posted
2 days ago
Duration
Format
Tutorial
educational
Views
1.8K
80 likes
Big Idea

The argument in one line.

Next.js 16.3 recovers single-page-app-level instant navigation on top of server rendering by letting developers decide, per piece of data, whether to stream it, cache it, or block on it, and by prefetching a reusable route shell instead of re-rendering the whole page on every click.

Who This Is For

Read if. Skip if.

READ IF YOU ARE…
  • You build with Next.js App Router and have noticed client-side navigations feel sluggish compared to older SPA frameworks.
  • You want to understand the historical trade-off between single-page apps and server-rendered apps before adopting a fix.
  • You're evaluating whether to turn on Next.js 16.3's cacheComponents flag and want to see the error messages and fixes it forces on you.
  • You want a mental model (stream, cache, or block) for deciding how to handle each async data dependency on a page.
SKIP IF…
  • You don't work with Next.js or React Server Components — the entire fix is App-Router-specific.
  • You want a finished, production-ready reference implementation rather than a live, in-progress demo with visible errors.
TL;DR

The full version, fast.

Server-rendered Next.js apps traded single-page-app speed for better SEO and security, but that meant every link click waited on a fresh server round trip. Next.js 16.3 fixes this with cache components: instead of prefetching or rendering the entire page, it prefetches a reusable shell per route and lets developers mark each async data source as stream (Suspense fallback), cache (use cache directive for static data), or block (rare, full wait). Enabling the cacheComponents flag forces every uncached dynamic read to be explicitly handled, which pushes toward smaller, composable per-data components. A companion partial-prefetching flag and a new Navigation Inspector devtool make the resulting shell-vs-live-data split visible and debuggable.

Free for members

Chat with this breakdown — free.

Sign in and you get 23 free chat messages on us — ask for the hook, quote a framework, find the exact transcript moment, generate a markdown action plan. Bring your own key when you want unlimited.

Create a free account →
Chapters

Where the time goes.

00:0000:45

01 · The Old Way: Why Navigations Feel Slow

Cold open on the pain point: clicking a link in the App Router waits on a server round trip, which is why developers moved toward SPA-style instant navigation in the first place.

00:4504:31

02 · SPA vs Server: The Pendulum History

Rewinds through web history: fully server-driven pages were clunky, so SPAs (React/Vue/Angular) front-loaded JS for instant clicks but paid for it with slow first loads and bad SEO. React Server Components swung the pendulum back to the server, restoring fast loads and SEO but losing the SPA-instant click feel.

04:3104:46

03 · Next.js's Earlier Fix Backfired

An earlier Next.js attempt to fix slow navigations by aggressively prefetching every link on screen destroyed server bandwidth and cluttered the network tab.

04:4605:46

04 · The New Mental Model: Stream, Cache, or Block

Next.js 16.3 steals what worked from SPAs: partial prefetching quietly preloads a usable shell per route, shows it instantly, then streams in dynamic data via Suspense — giving SEO and performance together with SPA-like click feel.

05:4610:44

05 · Live Demo: Adding Cache Components to Nextlearn

Builds against a demo course-platform site. Enabling cacheComponents throws an uncached-data error; the fix is to cache static reads (getCourse, getCourses) with use cache and wrap the genuinely live read (getLiveStats) in a Suspense-bound LiveEnrollment component. Extracting a CourseHeader and Syllabus component the same way turns the page into a thin, composable layout.

10:4412:04

06 · Partial Prefetching + the Navigation Inspector

Enabling the partial-prefetching flag switches Next.js from prefetching a shell per exact request to one reusable shell per route. The new Navigation Inspector devtool visualizes that shell live, and the video closes with a free Next.js mistakes cheat sheet and a pointer to a related video.

Atomic Insights

Lines worth screenshotting.

  • Single-page apps front-load a massive JavaScript bundle so first load is expensive, but every subsequent navigation feels instant because the browser already has the code.
  • Server-rendered apps (like Next.js App Router with server components) flip that trade: fast, SEO-friendly first loads, but every link click re-triggers a full server round trip and can feel slow.
  • Next.js 16.3's fix is not full prefetching of every page — an earlier aggressive-prefetch attempt destroyed server bandwidth and was rolled back.
  • The new approach prefetches one reusable shell per route and reuses it, instead of re-fetching or re-rendering the entire page on every navigation.
  • Enabling the cacheComponents flag in next.config immediately throws an error on any uncached dynamic data during prerendering, forcing an explicit decision per data source.
  • There are exactly three ways to handle a piece of async data under cache components: stream it inside a Suspense boundary, cache it with the use cache directive, or let the route block (rarely the right choice).
  • The decision should be made per async request, not per page — ask whether this specific piece of data (title, description, live seat count) actually changes on every request.
  • Wrapping only the genuinely dynamic pieces (like a live enrollment count) in Suspense, while caching the static content (title, description, syllabus), lets the page ship a cached shell instantly and stream in only what's truly live.
  • A forced side effect of adopting cache components is a more composable page architecture — the page becomes a thin layout of independent components, each responsible for fetching and caching its own data.
  • Next.js 16.3 ships a Navigation Inspector devtool that visualizes the shell shown during navigation; an empty shell means the instant-navigation experience will look like a blank flash instead of a fast transition.
Takeaway

Fix slow navigations by deciding per data source, not per page.

WHAT TO LEARN

Instant navigation in a server-rendered app comes from prefetching a reusable shell per route and explicitly choosing, for every async data source, whether it streams, caches, or blocks.

01The Old Way: Why Navigations Feel Slow
  • The pain point behind every fix in this video is a real one: App Router navigations wait on a server round trip per click, which reads as 'slow' compared to SPA-era expectations.
02SPA vs Server: The Pendulum History
  • Single-page apps trade an expensive first load for instant subsequent navigations by shipping the JavaScript bundle upfront; server-rendered apps trade that back for fast first loads and SEO, at the cost of slower per-click round trips.
  • Neither architecture is strictly better — each optimizes for a different moment in the user's session (first load vs. every subsequent click).
03Next.js's Earlier Fix Backfired
  • Full prefetching of every possible page destroys server bandwidth — the fix isn't to prefetch more, it's to prefetch a smaller, reusable shell per route.
04The New Mental Model: Stream, Cache, or Block
  • When forced to classify data as static or dynamic, most fields on a page (titles, descriptions, syllabi) are actually static and only change on a new deploy — treat them as cacheable by default.
  • Reserve true dynamic handling (Suspense streaming) for data that must be live on every request, like a real-time seat count or inventory level.
05Live Demo: Adding Cache Components to Nextlearn
  • A caching error that forces you to isolate one data source per component is a forcing function toward better architecture, not just a build hurdle to route around.
  • Splitting a page into per-data-source components (header, syllabus, live enrollment) makes each piece independently cacheable or streamable.
06Partial Prefetching + the Navigation Inspector
  • Debugging an instant-navigation feature means inspecting what's actually inside the cached shell — an empty shell means users see a blank flash instead of a fast transition, so verify the shell's contents, not just that caching is enabled.
Glossary

Terms worth knowing.

Single-page application (SPA)
A web app architecture that downloads a large JavaScript bundle upfront, then swaps UI in the browser on navigation without full page reloads, making clicks feel instant after the first load.
React Server Components (RSC)
A rendering model where components run on the server and ship pre-rendered HTML/data to the browser, reducing client-side JavaScript and improving SEO and initial load time.
Cache components
A Next.js 16.3 feature (enabled via a config flag) that requires every piece of dynamic data on a prerendered route to be explicitly marked as cached, streamed, or blocking.
use cache directive
A Next.js directive applied to a function or component that marks its output as cacheable, so it can be served instantly from a reusable route shell instead of being recomputed on every request.
Suspense boundary
A React mechanism that shows a fallback UI while an async component is still loading, letting the rest of the page render without waiting on that one piece of data.
Partial prefetching
A Next.js 16.3 flag that prefetches and caches one reusable shell per dynamic route (rather than one shell per specific request), balancing instant navigation against server load.
Navigation Inspector
A panel in Next.js DevTools that shows the cached shell served during a navigation before live/dynamic data streams in, used to debug whether a route's instant-navigation shell is meaningful or empty.
Resources

Things they pointed at.

07:06linkNext.js Mistakes Cheat Sheet (free download)
11:41linkRelated video: how senior engineers build with AI (media-feed system design)
Quotables

Lines you could clip.

00:00
We have all been burned by how Next.js's app router can sometimes feel really slow, especially navigation.
universal developer pain point, tight cold openTikTok hook↗ Tweet quote
05:06
So server components made our highly dynamic web apps feel like slow heavy websites again.
sharp, quotable diagnosis of the RSC trade-offIG reel cold open↗ Tweet quote
08:15
The Next.js team looked at the traditional SPAs and decided to steal what worked in the SPA world.
clean one-line summary of the 16.3 strategynewsletter pull-quote↗ Tweet quote
10:34
The error has forced us into creating a more composable architecture.
counterintuitive insight — a build error improving the codebaseTikTok hook↗ Tweet quote
The Script

Word for word.

Read-along

Don't just watch it. Burn it in.

See every word as it's spoken — crank it to 2× and still catch all of it. The same dual-channel trick behind Amazon's Kindle + Audible.

metaphor
00:00Let's be honest. We have all burned by how Next. J's app router can sometimes feel really slow, especially navigation.
00:06If you have a bunch of links and you click one of them, you have to wait for the server to respond and then finally your next page will load. And that is incredibly slow. And which is why we all truly loved and moved towards SPA, that is single page application.
00:21With single page applications, all the links are preloaded and when you click on it, it automatically just shows the page to us right away. It feels incredibly fast. But as we move towards server components and started using Next.
00:33Js app louder a bit more, the links felt really slow. But finally, I have some good news for you because Next.
00:40Js 16.3, which is coming out very soon, has a fix for this exact issue. Now links no longer feel slow.
00:47So if you have like a custom course platform that you're building or if you're rendering a bunch of links, then they are going to feel very instant with instant navigations inside of Next. Js.
00:57This is going to bring the spa level speed with navigation and links inside of the Next. Js app router, so your app is going to feel really fast. By introducing cache components and fundamentally changing how prefetching works, reusing the route shells instead of fetching the entire page every single time, some of the fixes that Next.
01:16Js 16.3 has introduced, and honestly, I'm really excited for it. So in this video, I'm going to quickly give you a deep dive into how this new mental model, stream, cache, or block actually works. So grab a cup of coffee and let's finally kill those loading spinners.
01:30So let's dive in. To understand why next year's sixteen point three is such a big deal, we have to rewind for a second and talk about why single page applications or SPA were invented in the first place. Now back in the day, the web was entirely server driven.
01:44If you click the link on a specific website, then the browser completely dumped the current page, stared, the user then stared at a white screen and it waited for the server to build and send back a brand new HTML document, and the user will then see that specific document. It was clunky, it was jarring, and it honestly felt incredibly slow.
02:03Because frameworks like React, Vue, Angular, they fundamentally changed the game for us. Instead of asking the server for a brand new HTML page every single time, what a spa did is that it downloaded the JavaScript necessary in the form of a massive bundle upfront.
02:20So the user now has all the JavaScript downloaded in their browser and because now the browser has all the code necessary, when the user clicked the link on the page, JavaScript intercepted the click, it swapped out the UI components and then showed you a shell of the next page while quietly fetching things in the background, reading for the server for the data.
02:42The result from this was the navigations felt instant. Apps felt really snappy. Apps felt like native desktop software.
02:50Users loved it. But there's a catch in this thing. Sending massive amounts of JavaScript to the browser meant that the initial load time was terrible.
03:00The first load was really expensive. If you have high speed Internet, it's great, but phones on their different networks, three g network or four g network, struggle to parse the specific code.
03:13And SEO, that is search engine optimization, was essentially a nightmare because web crawlers, all they could see is a specific shell that is a blank page, which is why React server components were born.
03:25So the pendulum swung back. Next. Js and the React team introduced the Next.
03:31Js app router and React server components. The power was back in server's hand. So the goal was let's move the heavy lifting back to the server so we can ship zero JavaScript to the client because browsers not that powerful on all devices.
03:48So when a user clicks the link, that entire HTML document in fact shipped from the server to the browser and as a result, we got really fast initial load times, great SEO, and great data security because now the server has full control.
04:03It has all the data. But we lost something huge in this process. We lost the spa magic.
04:08Remember how navigations felt so instant? Users saw the next page immediately. They didn't feel like they were waiting too long.
04:15So many developers rightfully complain that we have accidentally time traveled back to the good old days where we are leaning on the server for everything. So server components made our highly dynamic web apps feel like slow heavy websites again.
04:32Now Next. Js tried to fix that in a previous version aggressively by prefetching every single link on the screen, but that just destroyed the server bandwidth and the network tabs, which brings us to Next.
04:44Js 16.3. Now the voice mail team looked at the traditional spas and decided to steal what work in terms of spas, like what work in in the spa world. Instead of generating every single page on the server beforehand and then showing it to the user, Next.
05:01Js now uses something called as partial prefetching. It quietly preloads a usable shell for your routes. So if a user clicks a link inside of Next.
05:11Js 16.3, it behaves exactly like a spa. It instantly shows you a cached UI so that the user has something to look at.
05:20It gives the user immediate visual feedback while the server then streams in the dynamic data in the background using suspense boundaries which you may have heard of. So you're finally getting the holy grail, the SEO and the performance of a server rendered app with snappy instant click feel of a single page application.
05:41So that is exactly what instant navigations inside of Next. Js is essentially fixing. And they have three different ways to fix that.
05:49Let me show you exactly how how we can set this up and show you examples via this mini custom course platform that I built. So this is a simple course platform.
05:58It is not very fast. It's a little slow because we don't have instant navigation here yet, but you can essentially see these are the different lessons in the course and some syllabus and some dummy data here. So if we go back to the code, let's take a look at this specific dynamic route here.
06:13And this is in fact a dynamic route, slow courses slash instant navigation. If I click the next link, it's another dynamic slug and so on. We are trying to get the course data.
06:22We are trying to get live stats. We're throwing a not found error if there is no course and then rendering that content onto the page. If you take a look at get course or get courses or get live stats, for example, I'm just adding a dummy timer here to simulate what the server would send back to us as well.
06:40So you can pretend that this is a slow database or CMS read or something like that. Now all these best practices, if you just want your agents to just get trained on specific skills, then I have also released a next year's mistakes cheat sheet so agents can know exactly what not to repeat so you don't have to keep prompting them over and over again.
06:58Take a link in the description below so you can download it for free. Now let's start by enabling instant navigation. And to do that, we have to enable cache components.
07:06Let's go to the next config file and over here, let's just set cache components as true. Now Now let's watch what happens. So we get this error saying that Next.
07:16Js encountered uncached data during prerendering. Because there's dynamic data, it's not cached. That's why we get this error.
07:22There are two different ways you can fix this. One is to stream and to wrap it inside a suspense boundary so we can show a fallback UI to the user. We could cache that component or data or we can allow a blocking route.
07:33So for example, if you go back to our diagram here, there are three options. Suspense boundary, that means we can show a loading state whenever there's asynchronous data. Cache it, that means we can show some sort of a cached UI to the user or blocking, which means that we don't wanna ever show the loading shell at all to the user.
07:51So this is where we need to ask ourselves. You know, don't need to make a choice for the entire page, but make it per asynchronous request. If you take a look at each piece of data and ask, does this actually change?
08:03If you take a look at the course page, the title, the description, even the instructor can actually be static. The they only change when we I ship a new lesson, so I'm fine taking off a new build anytime that happens.
08:16The syllabus is the same thing. It can be static easily. But what cannot be static and is genuinely dynamic are how many learners are taking the specific course, how many seats are left.
08:26That number should update in real time. So we can cache the static stuff but stream in the dynamic stuff later on, which is exactly what Spas did. The approach is to cache first.
08:35So we can get live stat functions, stay uncached because we actually want it live. If we leave it uncached, the error will come back. So that's what we can do is let's just cache the data.
08:45You have these two functions. So let's just go to get course and let's cache it.
08:51Then even get courses, let's cache it. Get live stats. Let's wrap it in a suspense boundary.
08:57So let's just copy this, and we can create on a component called as live enrollment. Let's just call live enrollment and then paste in the code.
09:06I copy. It. Passing in the params and the live stats, which is what makes it dynamic.
09:12And let's wrap it in a suspense boundary. And let's import suspense from React. Now we could pretty much get rid of this line altogether.
09:20If we go back, refresh the page, you are now going to see that it's complaining for some other lines, so we'll get back to that. But if I click on, let's say, instant navigation, we are going to see loading live, master loading live enrollment, cache components loading live, but rest of the content is readily available and the navigations are in fact instant.
09:41And if you go look at the error, it says that this specific slug parameters also blocks the entire page. So for that, we could do something similar. If we take a look at course, this is the header as well as course as these lessons as well that we have.
09:56So we could simply also create a course header component and wrap it in a suspense boundary. And let's create a course header component as well.
10:06Similarly, let's do something similar for syllabus. Create a component called as syllabus and paste in the syllabus as well. Now we could get rid of this altogether and the slug and the minute we do that, this component doesn't need to be async anymore.
10:22So now the error is gone and we have replaced it with suspend boundary. Data that can be cached is also cached. And the important side effect here is that error has forced us into creating a more composable architecture.
10:33The page is now a thin layout of independent components, each responsible for its own data, which is pretty amazing. Now there's one more flag that we could enable, and that is the flag for partial prefetching. Let's enable that and see what happens.
10:46If you go to next config, we could essentially just enable partial prefetching. Every time for a dynamic route, Next. Js would not prefetch one reusable shell per route and cache it.
10:57Instead, it would prefetch for every single request. So for example, if there are thousand lessons, it would prefetch the shell for a thousand lessons.
11:05By just simple one shell fix, made the framework more performant. And it also shipped Next. Js dev tools.
11:13So you are going to see navigation inspector here. Let's just run that. And if I refresh the page, you're gonna see what would happen whenever the navigation pauses.
11:23This is a shell. The next net Next. Js is going to show the user.
11:27Obviously, replace it with nice skeletons for the user. But the minute I hit resume, the content is displayed. So it works like a debugger for navigation, and I would get in the habit of checking this whenever you batch a route because the shell is your instant experience.
11:41If the shell is empty, your instant navigation is a instant black box. And if you like this video as next steps, definitely check out this video on how some senior engineers actually build with AI. Because let's be real.
11:53I feel like that's where the world is heading. So I wanna show you architecturally how we could design a complex system like a media feed like TikTok or Instagram. Alright.
12:01Thank you so much for watching. Bye for now.
The Hook

The bait, then the rug-pull.

Every Next.js developer knows the feeling: you click a link in an App Router project and watch a beat of dead air before the next page shows up. This walkthrough traces exactly why that happens — and why the fix Next.js 16.3 ships isn't just another prefetch tweak, but a new per-data-source mental model of stream, cache, or block.

Frameworks

Named ideas worth stealing.

07:30model

Stream, Cache, or Block

  1. Stream — wrap the data in a Suspense boundary and show a fallback UI while it loads
  2. Cache — mark static/rarely-changing data with the use cache directive so it's part of the reusable shell
  3. Block — let the route wait on the data with no shell shown at all (rarely the right call)

The decision framework Next.js 16.3 forces once cache components are enabled: for every async data dependency on a route, pick one of three handling strategies instead of treating the whole page as one unit.

Steal forAny Next.js App Router route that mixes static content (titles, descriptions, syllabi) with genuinely live data (seat counts, stock levels, live stats).
CTA Breakdown

How they asked for the click.

VERBAL ASK
07:06link
I have also released a Next.js mistakes cheat sheet so agents can know exactly what not to repeat... take a link in the description below so you can download it for free.

Soft mid-video lead-magnet drop, delivered in-context while discussing agent best-practices rather than as a separate ask; reinforced at the very end with a next-video recommendation.

Storyboard

Visual structure at a glance.

cold open
hookcold open00:00
the old way
hookthe old way00:13
16.3 teaser
promise16.3 teaser00:40
SPA bundle cost
valueSPA bundle cost03:05
stream/cache/block model
valuestream/cache/block model05:30
Nextlearn demo site
valueNextlearn demo site06:12
cacheComponents error + 3 fixes
valuecacheComponents error + 3 fixes07:08
Navigation Inspector demo
valueNavigation Inspector demo10:44
outro / CTA
ctaoutro / CTA11:59
Frame Gallery

Visual moments.

Chat about this