Журнал / Разработка веб-продуктов
Как работает кэширование в Next.js v13+ с помощью App Router

Подробный обзор того, как работает кэширование в Next.js 13+, какие типы кеша существуют и как это влияет на производительность и SEO.
Что такое кеш и как он работает в Next.js
Кеш - это способ хранения результатов вычислений или запросов, чтобы вам не приходилось их повторять, ускоряя работу вашего приложения. В Next.js можно кешировать HTML-страницы, данные, запросы, рендеринг компонентов и даже целые маршруты.
С появлением App Router (начиная с Next.js 13) философия изменилась: теперь кэширование включено по умолчанию, и это зависит от разработчика, чтобы отключить его там, где требуется динамическое поведение.
Политика Next.js состоит в следующем:
"Мы кешируем всё, если не сказано обратное"
Если вы явно не указали cache: 'no-store', next: { revalidate }, или dynamic = 'force-dynamic', то:
fetch()будет кешироваться- макет и страница также могут быть кешированы
- маршруты будут добавлены в кеш маршрутов
- рендеринг страницы попадет в Полный кеш маршрутов
Это обеспечивает производительность, но может привести к устаревшим данным и затруднениям в отладке.
Типы кэширования в Next.js

Источник: Документация Next.js
Полный кеш маршрутов (кэширование маршрутов с сервера)
Используется с ISR (Инкрементальная статическая регенерация).
- Вся страница кешируется (HTML, данные из
layout.tsx,page.tsx,fetch(),headers(),cookies()). - Кеш находится на сервере.
- Работает по умолчанию, если отсутствует динамическое поведение.
- Инвалидируется через
revalidateилиrevalidateTag().
Лучше всего подходит для блогов, маркетинговых страниц и другого редко изменяющегося контента.
Пример:
export const revalidate = 60; // regenerate the page every 60 seconds
Кеш данных (кэширование запросов с сервера)
- Ответы от
fetch()в компонентах сервера кешируются. - Контролируется с помощью
next: { revalidate }илиcache: 'no-store'.
Пример:
await fetch('https://api.com/posts', {
next: { revalidate: 300 },
});
Мемоизация запроса (кэширование памяти на запрос)
Это оптимизация внутри Next.js: один и тот же fetch() или функция с одинаковыми аргументами вызывается только один раз за рендеринг.
- В пределах одного серверного рендера Next.js отслеживает идентичные запросы.
- Если они уже были вызваны, результат берется из кэша в памяти.
- Работает независимо от
cache: 'force-cache'илиno-store.
Подходит для:
- DRY (не повторяйся), когда запрашиваются одни и те же данные в разных компонентах.
- Улучшения производительности без ручной оптимизации.
- Когда используется тот же
fetchкак вlayout.tsxтак и вpage.tsx.
Не подходит для:
- Переиспользования между различными запросами или пользователями (не глобальный кеш).
- Обход кеша запросов — это работает поверх Мемоизации запросов.
// lib/getUser.ts
export async function getUser() {
return fetch('https://api.com/user').then(res => res.json());
}
// app/layout.tsx
export default async function Layout({ children }) {
const user = await getUser(); // Call 1
return (
<div>
<Sidebar user={user} />
{children}
</div>
);
}
// app/page.tsx
import { getUser } from '../lib/getUser';
export default async function Page() {
const user = await getUser(); // Call 2, but actually not repeated
return <p>Hello, {user.name}</p>;
}
Физически, fetch будет вызван только один раз, и результат будет использоваться в обоих местах.
Кеш маршрутизатора (клиентский кеш)
Это кеш, который вы контролируете сами, используя библиотеки типа SWR, React Query и т. д.
- Работает только с клиентской навигацией (
<Link>,router.push()). - Next.js не контролирует этот кеш - вы сами решаете, как его кешировать.
- Очень быстро, потому что ничего не перерисовывается - React просто монтируется из памяти.
- Но он существует только до тех пор, пока пользователь не перезагрузит страницу (F5).
Лучше всего подходит для интерактивных компонентов, форм, панелей управления.
Пример:
'use client';
import useSWR from 'swr';
const { data } = useSWR('/api/data', fetcher);
Визуальное сравнение типов кэширования
| Тип кэширования | Где это работает | Управление | Пример |
|---|---|---|---|
| Полный кеш маршрутов | Сервер (весь маршрут) | перепроверять, тэг | export const revalidate = 60 |
| Кэш данных | Сервер (запрос) | кэш, перепроверять | fetch(..., { next: ... }) |
| Кэш статической генерации | Сервер (время сборки) | Нет | JSX без данных |
| Клиентский кэш | Браузер / клиент | Вы | SWR / React Query |
Реальный пример
Предположим, вы строите магазин:
| Страница | Что кэшировать | Какой тип кэша использовать |
|---|---|---|
/products | Список продуктов, обновляется каждые 5 минут | Кэш полного маршрута (ISR) |
/api/products | Данные API продукта | Кэш данных (с тегом перепроверки) |
| Навигация SPA | Быстрая навигация | Кэш маршрутизатора (клиентский кэш) |
Общие проблемы кэширования в App Router
Обновленные данные — но сайт отображает старые данные
fetch() использует force-cache по умолчанию, если не указано cache: 'no-store' или next: { revalidate }. В результате Next.js кэширует данные и никогда их не обновляет.
Решение:
- Добавьте
cache: 'no-store'для отключения кэширования - Или
next: { revalidate: 60 }для ISR
fetch('https://api.com/data', { next: { revalidate: 60 } });
URL (searchParams) изменился, но данные остались теми же
Next.js не перерисовывает запрос fetch, если URL остается тем же. Если используете параметры, добавьте их непосредственно к URL запроса fetch:
fetch(`https://api.com/posts?category=${searchParams.category}`, {
next: { revalidate: 60 }
});
Переход через <Link>, но данные не обновились
Кэш маршрутизатора (клиентский кэш) был использован. Next.js не делает новый запрос при возвращении на страницу.
Решение:
- Принудительное обновление данных через
router.refresh() - Используйте
cache: 'no-store'если данные всегда должны быть свежими
revalidatePath() или revalidateTag() не работают
- Кэш не был создан (например, из-за
no-store) - Вы не используете
тегив fetch - Вы вызываете
revalidatePath()вне серверного действия
Решение:
- Убедитесь, что fetch использует
next: { tags: [...] } - Вызовите
revalidateTag('tag')в серверной функции
Макет кэшируется и не обновляется
layout.tsx также кэшируется в качестве RSC с перепроверкой, и если данные внутри кэшированы, они не обновятся до следующего ISR.
Решение:
- Используйте
cache: 'no-store'для fetch в layout.tsx, если, например, он содержит профиль пользователя - Или переместите fetch из макета на страницу (или клиентский компонент с SWR)
Неожиданное поведение в режиме разработки (dev)
В next dev, многие кэши отключены или работают по-другому, и перепроверка не работает надежно в режиме dev.
Совет:
Тестировать кеш с следующей сборкой && следующим запуском или предпросмотром Vercel.
Комбинация cookies(), headers(), params, и fetch() нарушает кеш.
Когда вы используете динамические вещи, такие как:
cookies()
headers()
useSearchParams()
generateMetadata() с динамическим
Next.js автоматически отключает кеш страниц и переключается на dynamic = 'force-dynamic'. Чеклист: как избежать проблем с кешем
Всегда явно устанавливайте поведение fetch:
- Не забудьте включить параметры запроса непосредственно в URL запроса
// no cache at all
fetch(..., { cache: 'no-store' })
// ISR (revalidate every 60 seconds)
fetch(..., { next: { revalidate: 60 } })
// manual invalidation via tag
fetch(..., { next: { tags: ['products'] } })
- Тестирование с
- следующей сборкой && следующим запуском
— в противном случае у вас может возникнуть ложное чувство уверенности.Если вам нужно вручную инвалидировать данные, используйте - revalidatePath()
илиrevalidateTag().Как работает кеширование в Next.js v13+ с App Router