Коротка відповідь. Instant Navigations у Next.js 16.3 – це не одна фіча, а нова дисципліна: кожен маршрут, який чекає на дані, тепер має явно обрати один із трьох станів. Stream – користувач миттєво бачить лоадер через <Suspense>; Cache – миттєво бачить кешований UI через 'use cache'; Block – export const instant = false, і навігація чесно чекає сервер. Плюс переписаний prefetch: замість запиту на кожен лінк у viewport – один reusable shell на маршрут. Усе вмикається флагами cacheComponents: true і partialPrefetching: true, які в майбутньому мажорі стануть дефолтом.
Проблема, яку нарешті визнали
Класична навігація в server-driven застосунку: клік → нічого → відповідь сервера → сторінка. Для блогу це нормально. Для застосунку – ні: саме через оцей «нічого» багато команд тікали в SPA, жертвуючи перевагами серверної моделі.
SPA вирішує це так: клік → миттєво каркас наступної сторінки → дані доїжджають. Next.js 16.3 переносить цю механіку в server-first модель – без відмови від Server Components.
Stream, Cache або Block: ментальна модель
Після ввімкнення cacheComponents: true кожен await даних у маршруті – це вибір:
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
cacheComponents: true,
partialPrefetching: true,
};
export default nextConfig;Stream. Обгортаєш повільну частину в <Suspense> – користувач миттєво отримує loading state, контент дострумлюється. Навігація інстантна, дані свіжі, але користувач бачить скелетон.
Cache. Позначаєш функцію 'use cache' – користувач миттєво бачить попередньо закешований UI. Навігація інстантна І з контентом, але контент може бути несвіжим до revalidation.
Block. Іноді ти СВІДОМО хочеш почекати сервер – наприклад, блог, який не хоче показувати скелетон замість статті:
// page.tsx
export const instant = false;Ключова зміна філософії: повільна навігація в dev – тепер помилка (Instant Insights автоматично підсвічує маршрути, які блокують), а не тихе «ну, так вийшло». Block лишається легальним станом, але явним рішенням, а не дефолтом через забутий Suspense.
Як обирати? Дуже схоже на вибір порогів у кешуванні взагалі: питання не «що швидше», а «хто володіє freshness». Котирування акцій – Stream (свіжість критична). Сайдбар чатів – Cache (учорашня назва чату нікого не вб'є). Юридичний документ – можливо, чесний Block.
Partial Prefetching: shell на маршрут, а не запит на лінк
До 16.3 Next.js слав prefetch-запит на кожен <Link> у viewport. Сайдбар із 20 чатами = 20 запитів, навіть якщо всі ведуть на той самий маршрут /chat/[id]. Команда сама визнає в анонсі: «виглядало безглуздо, і, чесно кажучи, ми згодні».
Нова модель запозичена у SPA: prefetch-иться один reusable shell на маршрут, кешується на клієнті на всю сесію і реюзається між усіма лінками цього маршруту. Концептуально – як per-route code splitting, тільки для UI-каркаса.
Якщо для конкретного лінка хочеться більше за shell (скажімо, хедер чату має «впасти» в UI миттєво) – <Link prefetch={true}> вмикає глибший per-link prefetch, але і він рендерить лише те, що доступно синхронно, відомо з URL (params/searchParams) або позначено 'use cache'. Тобто вибір більше не «все або нічого»: shell – базовий рівень, точковий prefetch – надбудова.
Бонус на майбутнє з анонсу: оскільки shells кешуються, команда досліджує offline-навігацію – маршрути, якими можна ходити при короткій втраті мережі.
Що з state між переходами
Shell реюзається, тому важливо розуміти межі: layout-и, які не змінились, зберігають свій React-state (це поведінка App Router, не новинка 16.3), а от усе, що в shell відрендерено «порожнім», при фактичній навігації добирає дані. Практичний наслідок: стан, який має пережити навігацію, живе в layout або в URL (searchParams), а не в page-компоненті – Instant Navigations роблять цю стару пораду ще актуальнішою, бо тепер між shell і повним контентом з'являється видима пауза, яку ти проєктуєш свідомо.
Як це тестувати, а не «відчувати на око»
Найнедооціненіша частина релізу – тестовий хелпер instant() для Playwright:
import { expect, test } from '@playwright/test';
import { instant } from '@next/playwright';
test('заголовок товару видно миттєво', async ({ page }) => {
await page.goto('/products/shoes');
// Асерти про те, що видно БЕЗ очікування мережі
await instant(page, async () => {
await page.click('a[href="/products/hats"]');
await expect(page.locator('h1')).toContainText('Baseball Cap');
await expect(page.getByText('Перевіряємо наявність…')).toBeVisible();
});
// А це вже після відповіді сервера
await expect(page.getByText('12 в наявності')).toBeVisible();
});Це переводить «навігація стала повільною після рефакторингу» з категорії скарг користувачів у категорію червоних тестів у CI. Додатково в DevTools з'явився Navigation Inspector – пауза навігації «на shell», щоб очима побачити, що саме prefetch-иться для маршруту.
Чесні trade-offs
- Пам'ять клієнта. Shells кешуються на сесію – для застосунку з сотнями маршрутів це пам'ять у браузері. Команда каже, що оптимізує prefetch далі; міряй свій кейс.
- Freshness.
'use cache'– це кеш з усіма наслідками: stale UI, стратегія інвалідації, read-your-own-writes після мутацій. Інстантність не безкоштовна – вона куплена або скелетоном, або несвіжістю. - Складність. Три стани × кожен маршрут = матриця рішень, якої раніше не було. Для лендинга це оверкіл; для продукту з щільною навігацією – саме та інженерія, якої бракувало.
- Статус tooling. В анонсі чесно перелічені known issues прев'ю (зокрема глюки Instant Insights у Safari – в dev радять Chrome/Firefox). Стабільний 16.3 вийшов 3 серпня 2026; семантику конкретних флагів перевіряй по актуальних docs свого мінора.
Команда Vercel обкатувала це на власному v0 і показує графік прискорення навігацій – але без абсолютних чисел у тексті, тож і я їх не наводитиму: запусти Instant Insights на своєму проєкті, він сам підсвітить твої повільні маршрути.
Типові помилки
- Увімкнути флаги і вважати справу зробленою. Флаги лише вмикають діагностику й нову модель – рішення Stream/Cache/Block по кожному маршруту ухвалюєш ти.
- Cache як дефолт для всього, бо «так інстантніше». Несвіжий баланс рахунку гірший за секунду скелетона.
export const instant = falseяк спосіб «заткнути» Instant Insights – це легальний інструмент для свідомого блокування, а не глушилка діагностики.- Ігнорувати
instant()-тести. Без них перший же рефакторинг layout-а тихо поверне повільні навігації.
Практичне завдання
Візьми свій Next.js-проєкт (або створи демо «каталог → сторінка товару») і пройди цикл: увімкни cacheComponents + partialPrefetching → подивись, які маршрути Instant Insights позначить повільними → для кожного ухвали явне рішення Stream/Cache/Block з однією фразою обґрунтування → закрий найважливішу навігацію instant()-тестом. Це рівно той воркфлоу, який тепер відрізняє «я чув про 16.3» від «я вмію ним користуватись».
Контекст ширше: базовий огляд рендерингу й кешування в Next.js – у гайді для співбесід, про вимірювання перформансу React без карго-культу – в розборі оптимізації, а про те, як TypeScript 7 прискорює сам цикл розробки, – у свіжому розборі Go-компілятора.