Next.js 16.3 arrives with a new feature bundle that makes page-to-page transitions feel nearly instant: Instant Navigations. In this guide you'll see step by step how to turn on the cacheComponents and partialPrefetching flags, how 'use cache' and <Suspense> work together during navigation, and how to migrate safely from 16.2 to 16.3. Instant Navigations aims to make your app feel as fast as a client-driven SPA while keeping the server-driven model's advantages.
💡 Pro Tip: Don't try to migrate all your routes at once the moment you flip oncacheComponents— advancing route by route withinstant = falseis the safest way to avoid breaking the build in one shot on a large App Router project.
Table of Contents
- Next.js 16.3 at a glance
- What Instant Navigations solves
- Turning on the cacheComponents and partialPrefetching flags
- Prefetching more than the shell
- How 'use cache' and Suspense work together
- Instant Insights panel and instant = false validation behavior
- Navigation Inspector and the @next/playwright instant() regression test
- Migration checklist from 16.2 to 16.3
- How to measure with Instant Insights
- FAQ
- How do I turn on Instant Navigations in Next.js 16.3?
- Which APIs break when cacheComponents is set to true?
- What's the difference between Partial Prefetching and loading.tsx?
- How do I safely upgrade from Next.js 16.2 to 16.3?
- Do I have to move my entire project to Cache Components to use Instant Navigations?
- Does the Instant Insights panel also run in production?
- Update (September 2026)
- Conclusion
- Sources
Next.js 16.3 at a glance
Next.js 16.3 was released as stable on August 3, 2026 (npm registry record: 16.3.0 → 2026-08-03T20:34:17Z). Instant Navigations, which ships with this release, isn't a single feature — it's a bundle of complementary tools: the Instant Insights panel, Partial Prefetching, the Navigation Inspector devtool, better ISR loading-shell behavior, and a dedicated Playwright test helper. The Next.js team also states explicitly that these behaviors will become the default in a future major release — meaning what you're testing today behind experimental flags is tomorrow's default.
As of August 14, 2026, when we wrote this article, the latest stable release on npm was 16.3.1 (published August 13) — so when you tell your project to "move to 16.3," in practice you're moving to 16.3.1. For patches after 16.3.1, see the Update section at the end of the article.
Version | Release date | Status as of August 14 |
|---|---|---|
16.3.0 | 2026-08-03 | Stable, first release of Instant Navigations |
16.3.1 | 2026-08-13 | Latest stable at that time |
What Instant Navigations solves
The App Router's server-driven architecture is strong for SEO and initial load performance; but transitions between links sometimes didn't feel as "instant" as a client-driven SPA. Instant Navigations closes that gap, adding SPA-level responsiveness without giving up the server's advantages.
Concretely: in 16.2, every link triggered its own prefetch request — even multiple links to the same route each got a separate request. In 16.3 this becomes a shared "shell" per route; links to the same route now share one prefetched shell.
The motivation isn't only performance — it's also developer experience. Previously, answering "why does this page feel slow" meant manually profiling and tracking down which link triggered an unnecessary prefetch. Since the Next.js team says these behaviors will become the default in a future major release, adopting cacheComponents and partialPrefetching now lets you migrate at your own pace instead of facing a forced big-bang jump later.
Turning on the cacheComponents and partialPrefetching flags
To try Instant Navigations, you need to turn on two flags in your next.config.ts file:
1// next.config.ts2import type { NextConfig } from "next";3 4const nextConfig: NextConfig = {5 cacheComponents: true,6 partialPrefetching: true,7};8 9export default nextConfig;cacheComponents replaces the flags you used to know as experimental.dynamicIO or experimental.useCache — if your project has either of these experimental settings, it's enough to replace it with cacheComponents: true. Once this flag is on, in the announcement's words, "when a route awaits some data on the server, you will be presented with a choice between a few options" — meaning for routes that wait on data on the server, you're required to clearly pick one of three options: Stream, Cache, or Block. For routes that keep rendering instantly, no extra work is needed.
partialPrefetching is separate: Next.js now extracts and prefetches a "reusable shell" once per route rather than per link; these shells are client-cached and shared across every link to that route, so each shell is fetched only once per session. For serverless cache patterns on the edge, see Hono.js: Serverless Web Framework Production Guide (in Turkish).
Prefetching more than the shell
With Partial Prefetching on, the default behavior is to fetch only the reusable shell for each distinct route in the viewport. But sometimes you want more than the shell — for example, having a chat page's title settle into place instantly. For that, you can opt into per-link prefetching by giving the relevant link <Link prefetch={true}>.
Even then, Next.js doesn't render the entire route as deep as possible: it only descends as far as content that's synchronously ready, known from the URL (like params or searchParams), or marked with 'use cache'. So prefetching is no longer "all or nothing" — the shell gives you the baseline, and <Link prefetch={true}> with 'use cache' adds more on top for the links you choose. In practice: deepen the two or three most-clicked links, leave the rest at shell level.
How 'use cache' and Suspense work together
While cacheComponents is on, you need to define the behavior of every server route segment that awaits data using one of three approaches:
- Stream: you wrap the data in a
<Suspense>boundary and stream it asynchronously; the user sees the shell immediately and content fills in as data arrives. - Cache: you put a
'use cache'directive at the top of the function and cache the result; when called again with the same input, Next.js returns it from cache. - Block: you deliberately keep the navigation server-bound — for that route segment you say "don't show the shell right away, wait for the data."
You can roughly summarize when to pick each of these three options like this:
Option | When to use it | What the user sees |
|---|---|---|
Stream | Data is slow but the rest of the page is ready (e.g. comments, recommendations) | Shell appears immediately, content fills in as data arrives |
Cache | Data doesn't change often and recomputing it is expensive (e.g. product description) | Content appears nearly instantly, served from cache |
Block | You don't want to show a loading shell for this route (e.g. a blog post page) | Page is held server-side until the data is ready |
Putting a route in the wrong category zeroes out the benefit: all-Block gains nothing, and you should handle user-specific data with 'use cache: private' instead of plain 'use cache' (plain 'use cache' is a cache shared on the server) — another reason to advance route by route.
1// app/products/[id]/page.tsx2import { Suspense } from "react";3 4type Product = { name: string; price: number };5 6async function getProduct(id: string): Promise<Product> {7 "use cache";8 const res = await fetch(`https://api.example.com/products/${id}`);9 return res.json();10}11 12function ProductSkeleton() {13 return <div aria-busy="true">Ürün yükleniyor…</div>;14}15 16async function ProductDetail({ params }: { params: Promise<{ id: string }> }) {17 const { id } = await params;18 const product = await getProduct(id);19 return (20 <article>21 <h1>{product.name}</h1>22 <p>{product.price} TL</p>23 </article>24 );25}26 27export default function ProductPage({ params }: PageProps<"/products/[id]">) {28 return (29 <Suspense fallback={<ProductSkeleton />}>30 <ProductDetail params={params} />31 </Suspense>32 );33}The pattern here isn't a coincidence. params is now a promise; in the official documentation's words, "you must use async/await or React's use function to access the values." The Cache Components guide goes further: pass the promise as a prop to the <Suspense> boundary instead of awaiting it at the top of the component, so a static shell can be produced even for params that aren't known yet. PageProps is a global helper you don't need to import separately; the types are generated during next dev, next build, or next typegen.
There's a critical point to watch here: a function marked 'use cache' (or any helper function it calls) cannot read request-scoped APIs like cookies(), headers(), or searchParams directly — you'll get a next-request-in-use-cache error. The fix is to read these values outside the cache and pass them into the function as parameters.
Instant Insights panel and instant = false validation behavior
The Instant Insights panel that ships with Next.js 16.3 automatically surfaces slow navigations — so you can see which route transition doesn't feel "instant" without manual profiling. On a large App Router project, this saves you from manually scanning dozens of routes: you just focus on where the panel points. Worth noting: marking a segment with instant = false removes it from validation entirely — in the documentation's words, "Setting instant = false on a segment opts it out of validation entirely." So routes you've deliberately left at Block won't produce warnings. This is useful during migration: you can silence with false the segments you've already decided on Block or haven't decided on yet, while tracking the remaining routes without noise.
Navigation Inspector and the @next/playwright instant() regression test
On the devtool side there's the Navigation Inspector: a tool for visually inspecting a navigation's loading shell. Use it when asking "why does the shell look empty/incomplete on this route" — it freezes the page at its initial load state, showing the static shell for direct visits and the prefetched target for client navigations. To see which Suspense boundary covers what, the docs recommend pairing it with React DevTools' Suspense panel.
On the testing side, Next.js provides a dedicated instant helper function for Playwright tests. This lets you write regression tests asserting whether a navigation actually came from a cached shell or from the server — so if someone accidentally drops a route back into Block mode, CI will catch it. The helper comes from the @next/playwright package and is used like this:
1import { expect, test } from "@playwright/test";2import { instant } from "@next/playwright";3 4test("product title is available immediately", async ({ page }) => {5 await page.goto("/products/shoes");6 7 // Verify what is visible without waiting for the network8 await instant(page, async () => {9 await page.click('a[href="/products/hats"]');10 await expect(page.locator("h1")).toContainText("Baseball Cap");11 await expect(page.getByText("Checking inventory...")).toBeVisible();12 });13 14 await expect(page.getByText("12 in stock")).toBeVisible();15});The distinction: assertions inside the instant() block are things that must be visible right after the click, before any network round trip — here both the new title and the "loading" state are verified. An assertion outside the block can only be satisfied once data arrives. This lets you (or a coding agent working on your behalf) pin down exactly what must appear instantly after every link click — a much stronger regression net than a vague "page loads" test.
Migration checklist from 16.2 to 16.3
Step | What to do | Why |
|---|---|---|
1. Run the codemod | npx @next/codemod upgrade | The official upgrade codemod; automates config and import fixes |
2. Replace the experimental flags | Replace experimental.dynamicIO / experimental.useCache with cacheComponents: true | These flags were merged into cacheComponents |
3. Clean up route segment configs | Remove the dynamic, revalidate, fetchCache exports | These exports error out once cacheComponents is on; use 'use cache' + cacheLife instead |
4. Migrate gradually | Mark routes that aren't ready with instant = false (can be done in bulk with a codemod) | Lets you advance route by route instead of migrating the whole project at once |
5. Build and test | next build + your existing test suite | Synchronous IO ( new Date(), Math.random(), crypto.randomUUID()) can still break prerendering |
Before running the codemod, make sure your project is in a clean git state; the codemod modifies files directly and you'll need to review the diff:
1# at the project root2git status --short3npx @next/codemod upgrade4git diff --statThe codemod doesn't resolve everything automatically — removing route segment configs and replacing them with 'use cache' is a step you do by hand. Behavior you used to define at the file level with dynamic, revalidate, or fetchCache exports is now defined at the function level, with a 'use cache' directive and cacheLife, once cacheComponents is on. In one sentence: a file-level static config becomes an explicit function-level cache directive. If your revalidate value doesn't map onto a built-in cacheLife profile ('seconds', 'minutes', 'hours', 'days', 'weeks', 'max'), pick the closest one or define your own. You no longer need fetchCache at all — every fetch inside 'use cache' scope is cached automatically.
For routes where you haven't yet made the Stream/Cache/Block decision, you can temporarily leave that route segment in its old (pre-Instant Navigations) behavior:
1// app/checkout/page.tsx2export const instant = false;3 4export default function CheckoutPage() {5 // Stays on the old, server-bound behavior until this route is ready6 return <CheckoutForm />;7}If you want to do this across the whole app in one pass, you don't need to walk every file by hand — there's an official codemod. It adds the opt-out to every page, layout, and default file that doesn't already declare instant:
1npx @next/codemod@canary cache-components-instant-false ./appIn a project using src/, you need to pass the path as ./src/app. Watch out: if you give the wrong path, the command doesn't error, it reports 0 ok — so make sure to check the file count in the output. The codemod skips files marked "use client" and files that already declare instant.
This turns migration from an "all or nothing" affair into something your team can move at its own pace, route by route. Don't skip step 4: explicitly mark the route you've left at Block with instant = false, because every Page and Default segment you don't mark keeps getting validated in development under the default validationLevel: 'warning'.
If you don't want to drive the migration by hand, the Next.js team mentions a "Skill" in the announcement, prepared for exactly this task — an official resource for adopting Cache Components in an existing app, whose steps you can have your agent run. The principles in Mobile DevOps Best Practices are also useful while revisiting your CI/CD pipeline for this change.
How to measure with Instant Insights
Here's how to measure it in your own project, step by step:
- After turning on the
cacheComponentsandpartialPrefetchingflags, start the Next.js dev server. - Navigate through the app in the dev server — Instant Insights surfaces slow navigations on its own; the validation shows you what's preventing a navigation to a segment from being instant: which navigation will block, where a
<Suspense>boundary is missing. - On the routes the panel flags, use the Navigation Inspector to visually examine why the loading shell looks incomplete or empty.
- Check which of the Stream, Cache, Block trio you assigned to the suspect route — the validation error names the blocking component; the fix is usually
use cacheor a<Suspense>boundary. - After fixing it, add a regression test for that route with the Playwright
instanthelper; that way, if someone accidentally drops the route back into Block mode later, CI catches it.
These steps let you answer "which page feels slow and why" using your own project's real data — instead of looking at a ready-made benchmark table. If you're building your route-level data layer with an edge-compatible ORM, Drizzle ORM + Turso: Edge SQLite Database Pattern is also worth a look.
GOLDEN TIP
The most valuable insight in this article
This tip holds the article's most important takeaway.
Easter Egg
You found a hidden gem!
There's a hidden detail in this section. Want to uncover it?
Reader Reward
We've put together the steps you shouldn't forget when moving to Next.js 16.3 as a one-page checklist; you can check off the items below one by one in your own project.
FAQ
How do I turn on Instant Navigations in Next.js 16.3?
You need to turn on two top-level flags in next.config.ts: cacheComponents: true and partialPrefetching: true. Once Cache Components is on, Next.js presents you with the Stream, Cache, or Block choice for routes that wait on data on the server (no extra work for routes that keep rendering instantly); data is either streamed with <Suspense>, cached with 'use cache', or the route is deliberately kept server-bound.
Which APIs break when cacheComponents is set to true?
First, the route segment configs (dynamic, revalidate, fetchCache) start erroring — 'use cache' and cacheLife take their place. Also, a function marked 'use cache' (or any helper it calls) throws a next-request-in-use-cache error if it reads request-scoped APIs like cookies(), headers(), or searchParams; on a dynamically rendered route this can pass next build and only surface under next start. The fix: read these values outside the cache and pass them in as parameters. Synchronous IO (new Date(), Math.random(), crypto.randomUUID()) also keeps breaking prerendering; not-ready routes can be temporarily marked instant = false.
What's the difference between Partial Prefetching and loading.tsx?
loading.tsx is a manual, static file, while Partial Prefetching is an automatic, route-based mechanism: Next.js automatically extracts a reusable shell from each route's UI, caches that shell once per route, and shares it across every link pointing to that route. Previously you had to manually define a loading.tsx for every route, or aggressively prefetch every link.
How do I safely upgrade from Next.js 16.2 to 16.3?
Run npx @next/codemod upgrade, accept the suggested codemods, then verify with build, test, and typecheck. For the move to Cache Components, gradual migration with instant = false is recommended over doing all routes at once; there's a cache-components-instant-false codemod for the whole app in one pass. Check the Update section for published security patches and which patch version to target. With a custom webpack config, third-party packages, or your own auth layer, test those by hand after reviewing the codemod's diff — it makes migration easier, it doesn't automate it.
Do I have to move my entire project to Cache Components to use Instant Navigations?
No. You can temporarily leave routes that aren't ready yet in their old behavior with the instant = false marker, and advance gradually route by route. This lets you benefit from Instant Navigations piece by piece on a large App Router project, without taking on the risk of one big migration all at once.
Does the Instant Insights panel also run in production?
No, the panel is a development-only tool. In the Next.js team's words, with Instant Insights "we've made slow navigations an error in development" — the panel lists them there. Actual prefetch behavior, per the same source, is "Like before, actual prefetching is only enabled in production." In practice: you inspect and fix the shell in development with the panel and the Navigation Inspector, then see prefetching's real effect in production.
Update (September 2026)
This article was prepared on August 14, 2026, when 16.3.1 was the latest stable release on npm. In the three weeks since, one development directly affects the "move to 16.3" advice: 16.3.3 (August 25, 2026) closed two critical security vulnerabilities in one release. The first was an unauthenticated remote code execution (RCE) bug (CVE-2026-75604, CVSS 9.0) on servers running a Windows file system, in apps using the Pages Router alongside the App Router without Cache Components; Linux and macOS weren't affected. The second was an unauthenticated RCE (CVSS 9.5) in the libheif library used by sharp, triggerable while optimizing an attacker-controlled AVIF image; once it surfaced, the patch schedule moved up a day, to August 25. 16.3.3 disabled AVIF optimization as a workaround; 16.3.4 (August 31, 2026) safely re-enabled it and brought additional build/test-mode fixes.
The practical takeaway: your target shouldn't be "move to Next.js 16.3" but upgrading to at least 16.3.4 — staying between 16.3.0 and 16.3.2 means staying exposed to two critical vulnerabilities. The Cache Components migration guide was also updated on August 25, 2026; check the official docs for the current gradual-adoption steps and the cache-components-instant-false codemod.
Conclusion
Next.js 16.3's Instant Navigations bundle isn't a single big feature; it's a whole you turn on with the cacheComponents and partialPrefetching flags, manage with the Stream/Cache/Block trio, and monitor with Instant Insights and the Navigation Inspector. instant = false is your safety net for gradual migration; if you're coming from 16.2, start with the codemod, advance route by route, and don't ignore the published security patches (see the Update section).
For a similar "cache-first" mindset on the edge, see Supabase Edge Functions: Serverless Backend with Deno Runtime (in Turkish). For how new architectures get adopted gradually on mobile, React Native New Architecture: Fabric, TurboModules, and Bridgeless Mode (in Turkish) covers a similar migration discipline. For serverless framework choices, Hono.js: Serverless Web Framework Production Guide (in Turkish), and for an edge-compatible data layer, Drizzle ORM + Turso: Edge SQLite Database Pattern round out this guide.
Sources
- Next.js 16.3 — General announcement and feature list of the Instant Navigations bundle
- Next.js 16.3: Instant Navigations — Primary source for the Stream/Cache/Block model, Partial Prefetching, and the Playwright instant() helper
- Migrating to Cache Components — The cacheComponents flag, route segment config restrictions, and instant=false gradual migration
- Next.js Codemods — Automated migration with
npx @next/codemod upgrade - August 2026 Security Release — Official disclosure and advisory links for the two critical RCEs closed in 16.3.3 (for the Update section)
- npm registry: next package metadata — Verification of publish timestamps from 16.3.0 to 16.3.4 in the
timefield (for the Update section)
Tags
iOS Development News
Weekly Swift tips, SwiftUI tricks and iOS best practices. No spam, only valuable content.
We respect your privacy. You can unsubscribe at any time.

