Когда данные в CMS или базе уже изменены, а страница Next.js продолжает показывать старую версию, важно определить, какой именно кеш удерживает результат. В App Router одновременно могут участвовать кеш запроса, готового маршрута и клиентского перехода.

Не лечите проблему глобальным force-dynamic без диагностики. Сначала проверьте источник данных и политику fetch, затем серверный Full Route Cache и только после этого Router Cache открытой вкладки. Инвалидация должна быть привязана к событию изменения данных.

Что проверить в первую очередь

Сначала зафиксируйте наблюдаемое поведение и не меняйте сразу несколько настроек. Важны точное время сбоя, адрес или сценарий, ожидаемый результат и последнее известное рабочее состояние. Так можно отличить причину от случайного совпадения и сохранить возможность быстрого отката.

  • Сравните прямой запрос к источнику данных и HTML страницы с нового приватного сеанса.
  • Уточните, используется App Router или Pages Router и какая версия Next.js развернута.
  • Найдите export revalidate, cache/no-store, unstable_cache, revalidatePath и revalidateTag.
  • Проверьте, вызывается ли webhook или server action после изменения данных.

Почему возникает проблема

У подобных сбоев редко бывает одна универсальная причина. На итог одновременно влияют конфигурация приложения, окружение, данные, кеш, права и внешние сервисы. Проверка должна идти от внешнего симптома к конкретному уровню, на котором впервые появляется неверное состояние.

  • fetch использует Data Cache с большим TTL или тегом, который никогда не инвалидируется.
  • Статически отрендеренный маршрут остается в Full Route Cache до следующей регенерации.
  • Открытая вкладка показывает Router Cache даже после серверной инвалидации.
  • revalidatePath вызывается с неверным путем или без динамического параметра.
  • Webhook приходит до фиксации данных, не проходит проверку подписи или завершается ошибкой.

Пошаговая диагностика

Диагностику проводите на копии или в контролируемое время. Перед изменениями сохраните конфигурацию, данные и журналы. Каждый шаг должен отвечать на один вопрос и оставлять измеримый результат: код ответа, запись в логе, состояние процесса, значение поля или воспроизводимый тест.

  • Добавьте временную метку источника и сборки, чтобы различать данные API и готовый HTML.
  • Откройте URL прямым запросом без client navigation и сравните результат после обновления.
  • Проверьте логи обработчика инвалидации, статус ответа и фактические tags/path.
  • Посмотрите заголовки CDN и reverse proxy: внешняя прослойка может держать HTML независимо от Next.js.
  • Повторите тест после router.refresh и в новой сессии, не используя это как окончательное исправление.

Какие уровни кеша нужно различать

Название revalidate часто используют как общее, хотя обновление разных уровней требует разных действий.

  • Data Cache хранит результат серверного fetch или кешированной функции и может инвалидироваться по времени или тегу.
  • Full Route Cache хранит результат рендера статического маршрута и зависит от данных, использованных при рендере.
  • Router Cache находится в браузере и влияет на клиентские переходы и уже посещенные сегменты.
  • CDN или reverse proxy может добавить четвертый независимый уровень с собственным TTL.
  • Кеш браузера для статических чанков должен работать по версионированным именам, а не мешать обновлению данных.

Как исправить проблему

Исправление лучше разбить на небольшие обратимые изменения. После каждого шага повторяйте исходный сценарий и проверяйте соседние функции. Если правка касается данных, сначала выполните ее на ограниченной выборке и сохраните журнал затронутых записей.

  • Назначьте cache policy каждому источнику: статичный, с TTL, по тегу или no-store.
  • После изменения сущности вызывайте revalidateTag для данных или revalidatePath для конкретного маршрута.
  • Проверяйте подпись webhook и выполняйте инвалидацию после успешного сохранения данных.
  • При server action обновляйте серверный кеш и согласованно обновляйте интерфейс через refresh.
  • Настройте CDN так, чтобы он не удерживал персональные или регенерируемые страницы дольше приложения.

Безопасный порядок внедрения

  • Сохраните резервную копию затрагиваемых файлов, базы и конфигурации, а также заранее опишите способ отката.
  • Воспроизведите сбой на тестовой записи, учетной записи или отдельном окружении без реальных платежей и рассылок.
  • Вносите по одному логическому изменению, фиксируя его в системе контроля версий или журнале работ.
  • Не отключайте права, проверку входных данных и защитные механизмы только ради исчезновения сообщения об ошибке.
  • После выкладки контролируйте логи, метрики и ключевой пользовательский сценарий, а не только открытие одной страницы.

Как проверить результат

Успешный разовый тест еще не доказывает исправление. Нужны повторный запуск, крайние случаи и проверка после очистки кеша, перезапуска процесса или новой сессии. Для критичных сценариев полезно сохранить автоматический тест или хотя бы короткий регрессионный чек-лист.

  • После изменения данные появляются в пределах заявленного TTL или сразу после события инвалидации.
  • Прямой запрос, переход внутри приложения и новая вкладка показывают одну версию.
  • Обновление одной сущности не сбрасывает весь сайт без необходимости.
  • Сбой webhook виден в логах и допускает безопасный повтор без потери события.

Типичные ошибки при исправлении

  • Добавлять Math.random или Date.now, чтобы случайно сделать маршрут динамическим.
  • Отключать весь кеш сайта вместо настройки конкретного источника.
  • Путать обновление Router Cache в браузере с серверной инвалидацией данных.
  • Вызывать revalidate до коммита базы и снова кешировать старое значение.

Как предотвратить повторение

Профилактика строится вокруг наблюдаемости и воспроизводимости: понятных конфигураций, контролируемых релизов, журналов без секретов и тестов на реальные сценарии. Важно не просто убрать текущий симптом, а сделать следующий похожий сбой заметным раньше пользователя.

  • Документируйте кеш-политику рядом с каждым источником данных.
  • Пишите интеграционный тест: изменение сущности, инвалидация, запрос страницы.
  • Логируйте тип, путь, тег и результат событий revalidate.
  • Мониторьте очередь webhooks и расхождение версии данных между API и страницей.

Что подготовить для разбора

  • Краткое описание ожидаемого и фактического поведения без паролей, токенов и персональных данных.
  • Точное время и последовательность действий, после которых появляется проблема.
  • Версии приложения, окружения и зависимостей, а также перечень последних изменений.
  • Фрагменты журналов с контекстом до и после ошибки; секреты в них необходимо скрыть.
  • Описание уже выполненных проверок и способ безопасно повторить проблему.

Частые вопросы

Поможет ли cache: no-store?

Он исключит Data Cache для конкретного запроса, но увеличит нагрузку и не исправит внешний CDN или клиентское состояние. Используйте его только для действительно динамичных данных.

Чем revalidateTag отличается от revalidatePath?

Тег инвалидирует связанные кешированные данные, а путь — конкретный маршрут. Выбор зависит от того, одна сущность используется на скольких страницах.

Когда нужна помощь специалиста

Если Next.js отдает старые данные и непонятно, где они задерживаются, я могу проследить источник, все уровни кеша и событие обновления, настроить точечную инвалидацию и проверить поведение после релиза.