Что Next.js предоставляет «из коробки»
- Кэш данных – В Next.js 13+ каждый вызов
fetch()попадает в кэш в памяти на время выполнения запроса. Добавление опцииrevalidateуказывает среде выполнения обновлять данные через определенный интервал, превращая «горячий» вызов API в «холодный» только тогда, когда это действительно необходимо. - Кэш всего маршрута – Фреймворк сохраняет отрендеренный HTML и данные, необходимые для всего маршрута. Повторные посетители видят мгновенный переход, так как сервер пропускает этап рендеринга.
- ISR – Статические страницы перегенерируются в фоновом режиме, пока старая версия продолжает обслуживать трафик. Это позволяет поддерживать большой сайт статичным без полной пересборки при каждом изменении контента.
- Кэширование в Server Component через
cache()– Хелперcacheот React мемоизирует ресурсоемкие вычисления или соединения с базой данных на время одного запроса, предотвращая дублирование работы внутри дерева компонентов страницы.
Эти кэши решают проблему «первого обращения», но все еще живут внутри процесса Node. Чтобы защитить сервер и базу данных, выносите кэширование на более внешние уровни.
Внешние уровни, которые можно добавить
| Уровень | Что хранит | Типичный инструмент | Как это помогает |
|---|---|---|---|
| CDN | Статические ресурсы, HTML, API JSON | Cloudflare, Akamai, AWS CloudFront | Перемещает контент на edge-локации, сокращая время отклика (round-trip) для пользователя |
| Reverse proxy | Ответы целых страниц до того, как они достигнут Node | Nginx, Varnish | Напрямую отдает закэшированные страницы, снижая нагрузку на экземпляр Next.js |
| Application-level cache | Результаты ресурсоемких запросов к БД или вызовов API | Redis, Memcached | Предоставляет быстрое хранилище «ключ-значение», которое сохраняется после перезапуска сервера и может использоваться несколькими экземплярами приложения |
Каждый уровень находится дальше от исходной базы данных, поэтому промах (cache miss) на одном уровне каскадом передается на следующий, и в конечном итоге запрос достигает базы данных только тогда, когда это абсолютно необходимо.
Поддержание актуальности кэша
Инвалидация (сброс кэша) — это то, на чем спотыкаются большинство команд. Хорошо работают три практических паттерна:
- На основе времени (TTL) – Назначьте фиксированный срок действия записи кэша. Просто настроить, но это может привести к выдаче устаревших данных до истечения таймера.
- Событийная модель – Подключитесь к вашей CMS или любому источнику данных, который отправляет вебхук при изменении контента. Вебхук инициирует очистку соответствующей записи кэша.
- На основе тегов – Привяжите логический тег к группе запросов
fetch(например,product-list). Когда любой элемент в этой группе меняется, один вызовrevalidateTag('product-list')очищает все записи, имеющие этот тег.
Комбинирование этих подходов позволяет найти баланс между актуальностью данных и частотой попаданий в кэш (cache-hit rate).
Иерархия, которая подходит большинству команд
- Кэш браузера – Статическим ресурсам (CSS, JS, изображениям) назначается длительный
max-age, чтобы устройство пользователя больше не обращалось к сети. - CDN – Edge-узлы кэшируют полные HTML-страницы и API JSON, соблюдая заголовки
Cache-Control, которые вы устанавливаете в Next.js. - Reverse proxy – Экземпляр Nginx или Varnish стоит перед сервером Next.js, отдавая закэшированные ответы для редко меняющихся маршрутов.
- Внутренний кэш Next.js – Кэши данных и маршрутов фреймворка отвечают за мемоизацию в рамках запроса и ISR.
- Кэш приложения – Redis хранит результаты тяжелых запросов к базе данных, используя в качестве ключей параметры запроса или теги.
- База данных – Первоисточник истины, к которому обращаются только при промахе кэша на всех вышестоящих уровнях.
Когда поступает запрос, он проходит по этому списку сверху вниз, пока какой-либо
