javascript

Вышел Next.js 16.4

  • пятница, 9 октября 2026 г. в 00:00:04
https://habr.com/ru/articles/1091748/

Эта статья перевод оригинальной статьи «Next.js 16.4».

Также я веду телеграм канал «Frontend по‑флотски», где рассказываю про интересные вещи из мира разработки интерфейсов и AI.

Вступление

В релизах ветки 16.x мы постепенно внедряли новую модель разработки, которая решает многие проблемы, с которыми вы сталкивались с самого появления App Router:

  • Обеспечивает быструю первоначальную загрузку даже персонализированных страниц.

  • Делает клиентские переходы в приложениях с серверным рендерингом мгновенными.

  • Делает кеширование декларативным и компонуемым, при этом включать его нужно явно.

Эта модель называется Cache Components, и в Next.js 17 она будет использоваться по умолчанию.

До этого релиза мы не рекомендовали её для всех без исключения приложений: в некоторых сценариях она не могла обеспечить те же гарантии по затратам и производительности, что и прежняя модель.

В этом релизе появились ключевые возможности, которые устраняют эти ограничения.

Начиная с Next.js 16.4, мы с уверенностью рекомендуем Cache Components как лучший выбор для любого приложения на Next.js.

С сегодняшнего дня Cache Components включены по умолчанию во всех новых приложениях, создаваемых с помощью create-next-app. Проекты, которые вы начинаете с нуля, могут пользоваться всеми преимуществами новой модели без каких-либо оговорок.

Для существующих приложений мы развиваем инструменты для ИИ-агентов, которые помогут перевести кодовую базу на новую модель. Новая команда next upgrade --agent предоставляет агентам инструкции по обновлению с учётом конкретной версии, а специализированные навыки (Skills) помогают выполнить рефакторинг, необходимый для перехода на Cache Components.

Next.js 16.4 также включает ряд улучшений, доступных из коробки для всех приложений на Next.js: меньшее потребление памяти и места на диске в режиме разработки, сокращённое время компиляции, более компактные продакшен-бандлы и обновление до React 19.3.

Далее полный обзор нововведений этого релиза. Начнём с Cache Components.

Что такое Cache Components?

Cache Components — это набор возможностей, позволяющий указывать, какие части дерева компонентов можно кешировать. Директиву 'use cache' можно воспринимать как аналог HTTP-заголовка Cache-Control, только на уровне компонентов:

import { cacheLife } from 'next/cache';
 
export default async function DashboardPage() {
  const currentUser = await getCurrentUser();
 
  return (
    <div>
      <p>Welcome, {currentUser.name}</p>
 
      <Suspense fallback={<Loading />}>
        <Projects userId={currentUser.id} />
      </Suspense>
    </div>
  );
}
 
async function Projects({ userId }) {
  'use cache';
  cacheLife('hours');
 
  const projects = await db.query.projects.findMany({
    where: eq(projectsTable.userId, userId),
  });
 
  return (
    <div>
      {projects.map((project) => (
        <p key={project.id}>{project.name}</p>
      ))}
    </div>
  );
}

При рендеринге страниц Next.js учитывает директивы 'use cache' и кеширует результат рендеринга компонентов в браузере (при клиентских переходах), а опционально ещё и на сервере (во время серверного рендеринга или заранее, на этапе сборки).

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

Подробнее о Cache Components читайте в руководстве по кешированию.

Что нового в Cache Components

В этой статье под Cache Components мы подразумеваем новую модель разработки, которую можно использовать уже сейчас, включив два флага в конфигурации Next.js:

import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
};
 
export default nextConfig;

Изначально Cache Components появились без частичной предзагрузки (Partial Prefetching), но теперь она тоже считается частью этой модели. Подробнее о ней можно прочитать в нашей статье о предыдущем релизе.

Теперь перейдём к тому, что нового появилось в Cache Components в версии 16.4.

Как гарантировать статичность оболочек, предзагружаемого контента и страниц

Одна из ключевых возможностей 'use cache' это создание страниц, на которых статический и динамический контент передаются потоком в рамках одного ответа сервера.

Например, можно добавить аватар текущего пользователя на страницу записи в блоге, которая в остальном предрендерится статически:

export default function Page() {
  return (
    <>
      <UserAvatar />
      <Content />
    </>
  );
}
 
// Этот компонент рендерится во время обработки запроса
async function UserAvatar() {
  const currentUser = await getCurrentUser();
 
  // ...
}
 
// Этот компонент предварительно рендерится статически
async function Content() {
  'use cache';
 
  await fetch('...');
 
  // ...
}

Next.js может отдавать предварительно отрендеренную запись в блоге из кеша (например, из папки /public вашего приложения или через CDN) и рендерить UserAvatar во время обработки запроса, это всё в рамках одного HTTP-ответа.

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

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

Например, чтобы страница записи в блоге из примера выше всегда оставалась статической и на неё нельзя было добавить динамический компонент вроде UserAvatar, мы могли бы добавить export const ensureStatic в файл маршрута:

export const ensureStatic = 'navigation';
 
export default function Page() {
  return (
    <>
      <UserAvatar /> {/* 🔴 Этот компонент ломает сборку */}
      <Content />
    </>
  );
}

Если установить ensureStatic в значение "navigation", Next.js завершит сборку с ошибкой, если на этой странице появится какой-либо динамический контент. Это гарантирует, что переходы на этот маршрут никогда не будут рендериться во время обработки запроса.

"navigation" это самый строгий режим, но при необходимости можно выбрать более гибкий вариант. Значение "prefetch" гарантирует, что ссылки с явно включённой предзагрузкой этого маршрута будут получать только статический контент, а "shell" что при первом обнаружении маршрута будет загружаться только его статическая оболочка.

ensureStatic можно задавать не только для отдельных страниц, но и на уровне layout, чтобы применить те же гарантии ко всем страницам внутри него. Например, можно добавить ensureStatic = 'navigation' в корневой layout и тем самым гарантировать, что все переходы между страницами на сайте будут статическими:

// app/layout.tsx
export const ensureStatic = 'navigation';
 
export default async function RootLayout({ children }) {
  // ...
}

Если со временем отдельным страницам понадобится динамический контент, ensureStatic можно перенести ниже, в соответствующие вложенные layout.

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

Подробнее в руководстве о том, как сохранять страницы статическими, и в документации по конфигурации ensureStatic.

Исключение контента из предзагрузки

Предзагрузка это мощный способ улучшить UX приложений на Next.js.

С помощью <Link prefetch> или useRouter().prefetch() можно заранее отрендерить закешированный интерфейс страницы ещё до фактического перехода на неё и тем самым избавиться от состояний загрузки.

Для примера рассмотрим простое почтовое приложение. Вот страница Inbox, которая отображает ссылки на каждое письмо:

async function Inbox() {
  const messages = await db.query.messages.findMany();
 
  return (
    <nav>
      {messages.map((message) => (
        <Link
          href={`/message/${message.id}`}
          key={message.id}
        >
          {message.subject}
        </Link>
      ))}
    </nav>
  );
}

А вот страница Message: при первой загрузке цепочки писем она показывает спиннер, а затем кеширует её в браузере для последующих посещений:

// app/message/[id]/page.jsx
export default function Page({ params }) {
  return (
    <Suspense fallback={<Spinner />}>
      {params.then(({ id }) => (
        <Message id={id} />
      ))}
    </Suspense>
  );
}
 
async function Message({ id }) {
  const [message, thread] = await Promise.all([
    getMessage(id),
    getThread(id)
  ]);
 
  return (
    <>
      <p>{message.subject}</p>
      <div>{message.body}</div>
 
      {thread.map((message) => (
        <div key={message.id}>{message.body}</div>
      ))}
    </>
  );
}
 
async function getMessage(id) {
  'use cache';
 
  return db.query.messages.findFirst({ where: eq(messages.id, id) });
}
 
async function getThread(id) {
  'use cache';
 
  return db.query.messages.findMany({
    where: eq(messages.threadId, id),
    orderBy: asc(messages.createdAt),
  });
}

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

Чтобы убрать это начальное состояние загрузки, можно добавить prefetch к ссылкам на странице Inbox:

async function Inbox() {
  const messages = await db.query.messages.findMany();
 
  return (
    <nav>
      {messages.map((message) => (
        <Link
          prefetch
          href={`/message/${message.id}`}
          key={message.id}
        >
          {message.subject}
        </Link>
      ))}
    </nav>
  );
}

Теперь каждая ссылка будет предзагружать все закешированные данные и UI страницы Message сразу после того, как попадёт в область видимости. К моменту клика пользователя всё уже будет готово.

С точки зрения UX это отлично: состояния загрузки исчезают. Но есть и обратная сторона, теперь каждая видимая ссылка заранее загружает всю цепочку сообщений, даже если пользователь так и не откроет это письмо. Для нашего почтового приложения это может оказаться слишком дорого или создать лишнюю нагрузку на серверы.

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

В Next.js 16.4 это как раз стало возможным. Новый API navigation позволяет исключать закешированный контент из предзагрузки и тем самым откладывать его загрузку до реального перехода.

В нашем примере можно вынести цепочку сообщений в отдельный компонент и добавить await navigation(), чтобы исключить её из предзагрузки:

import { navigation } from 'next/cache';
 
async function Message({ id }) {
  const message = await getMessage(id);
 
  return (
    <>
      <p>{message.subject}</p>
      <div>{message.body}</div>
 
      <Suspense fallback={<Spinner />}>
        <Thread id={id} />
      </Suspense>
    </>
  );
}
 
async function Thread({ id }) {
  await navigation();
  const thread = await getThread(id);
 
  return (
    <>
      {thread.map((message) => (
        <div key={message.id}>{message.body}</div>
      ))}
    </>
  );
}

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

Помимо navigation(), мы также добавили prefetch(). Его можно использовать с await, чтобы исключить из оболочки маршрута закешированный контент, который иначе был бы загружен заранее. В таком случае его рендеринг откладывается до явной предзагрузки через <Link prefetch> или useRouter().prefetch().

Эти API дают больше контроля над тем, какие данные загружаются на разных этапах перехода, и позволяют подобрать оптимальный баланс между предварительным и отложенным рендерингом именно для вашего приложения.

Подробнее в руководстве по переносу работы на более поздний этап, а также в документации по API navigation и prefetch.

Новые возможности для ИИ-агентов

Мы продолжаем развивать инструменты для ИИ-агентов, чтобы Next.js стал системой, которая постоянно помогает поддерживать приложение в актуальном и безопасном состоянии. В Next.js 16.4 мы расширили документацию, Skills и инструменты проверки новыми возможностями для обновления через агентов и механизмами обратной связи. Это помогает нам лучше понимать, как вы разрабатываете приложения, и использовать эти знания для дальнейшего улучшения Next.js.

Обновление с помощью агентов

Новая опция --agent для next upgrade позволяет агенту провести обновление приложения от начала до конца. Команда проверяет установленную версию, выбирает целевой релиз и подготавливает для агента руководства по миграции, необходимые codemod-скрипты и шаги проверки. После этого агент применяет обновление, решает возникшие при миграции проблемы и проверяет, что приложение продолжает работать.

Запустить команду можно вручную или через агента из директории приложения:

npx next@canary upgrade --agent=latest

Использование next@canary запускает самую свежую версию инструментов обновления, даже если ваше приложение работает на более старой версии Next.js. Благодаря этому агент получает актуальные инструкции и может обновить приложение до последнего релиза.

Обновиться до актуальной версии это только первый шаг. Чтобы в дальнейшем не отставать от новых релизов, в Next.js 16.4 появился experimental.agentUpgrade. Когда вы или ваш агент запускаете next dev или next build, Next.js автоматически сообщит о доступном релевантном обновлении, теперь больше не нужно каждый раз проверять это вручную. Если вы решите обновиться, будет запущен тот же агентный workflow с учётом заданной вами политики.

Эти напоминания можно настроить в конфигурации Next.js:

import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  experimental: {
    agentUpgrade: 'security',
  },
};
 
export default nextConfig;
  • 'security' (политика по умолчанию): напоминает об обновлениях, которые устраняют известные уязвимости, затрагивающие установленную у вас версию.

  • 'latest': напоминает о новых major- и minor-релизах и использует политику обновления latest, чтобы приложение оставалось актуальным.

  • false: отключает напоминания об обновлениях.

Мы также работаем над новой политикой для этого флага, которая поможет агентам корректно внедрять новые возможности и изменения модели разработки, например, переходить на Cache Components. Уже сейчас можно использовать наши Skills для перехода на Cache Components и Partial Prefetching, чтобы агент помог вам мигрировать на новую модель.

Подробнее в руководстве по обновлению с помощью coding-агента и документации по конфигурации agentUpgrade.

Обратная связь от агентов

Во время разработки и обновления приложений coding-агенты нередко сталкиваются с ошибками фреймворка, неясной документацией или необходимостью использовать обходные решения. Новый экспериментальный механизм обратной связи позволяет агентам подготавливать черновики отчётов, которые вы можете проверить и при желании отправить команде Next.js.

Agent Feedback включён по умолчанию при создании нового приложения с рекомендуемыми настройками create-next-app. Для существующих приложений его можно включить через конфигурацию Next.js:

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    agentFeedback: true,
  },
};

export default nextConfig;

После включения этой опции next dev добавляет инструкции для агента, чтобы тот фиксировал потенциальные проблемы во время работы. Когда задача завершена, агент подготавливает черновики отчётов и открывает их в браузере для проверки.

Агенту явно указывается не включать в отчёты исходный код, логи, секреты и детали, специфичные для проекта. Каждый отчёт можно отредактировать или удалить, а данные не будут отправлены, пока вы сами не нажмёте Send feedback.

Agent Feedback требует включённой телеметрии Next.js и не работает в CI.

Подробнее в документации по обратной связи от агентов и конфигурации agentFeedback.

Улучшения для всех приложений

Меньший размер дискового кеша

В версии 16.4 дисковый кеш Turbopack занимает на 20–25% меньше места, при этом никаких изменений в конфигурации не требуется.

Теперь для данных, которые занимают большую часть кеша, используется сжатие Zstandard, а для метаданных по-прежнему применяется LZ4, чтобы сохранить высокую скорость поиска по кешу. Кроме того, мы улучшили механизм compaction, благодаря чему устаревшие данные удаляются эффективнее.

Ленивый server HMR

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

В 16.4 Turbopack компилирует и применяет серверные обновления только тогда, когда они действительно нужны для обработки запроса. Страница, которую вы сейчас просматриваете, по-прежнему обновляется сразу во время редактирования, а остальные маршруты ждут следующего обращения к ним. Это снижает объём лишней фоновой работы при навигации по приложению.

Общий runtime Turbopack

Теперь runtime Turbopack поставляется в одном чанке, который используется всеми маршрутами. Это уменьшает объём загружаемых данных и повышает эффективность кеширования.

Подробнее об этом и других улучшениях чанкинга можно прочитать в нашей статье о chunking в Turbopack.

Более компактные production-бандлы

В Next.js 16.4 Turbopack генерирует более короткие имена классов CSS Modules в production, уменьшая размер самих стилей, а также HTML и JavaScript, которые на них ссылаются. В режиме разработки длинные имена сохраняются, чтобы упростить отладку.

Кроме того, Turbopack теперь использует export mangling: внутренние имена JavaScript-экспортов, связывающих модули между собой, сокращаются, что дополнительно уменьшает размер бандла.

React 19.3

Next.js 16.4 поставляется с React 19.3, в котором появились стабильные View Transitions и Fragment Refs, новый API browser() и другие возможности.

Полный обзор изменений можно найти в анонсе React 19.3.

Новые экспериментальные возможности

React Compiler на Rust

React Compiler автоматически оптимизирует рендеринг компонентов, снижая необходимость в ручной мемоизации. Его экспериментальная версия на Rust, представленная в Next.js 16.3, работает напрямую внутри Next.js, без использования Babel.

В версии 16.4 появился новый быстрый механизм проверки, который позволяет пропускать файлы, не нуждающиеся в оптимизации. Кроме того, компилятор больше не повторяет те же оптимизации при сборке Client Components для серверного рендеринга, что уменьшает объём работы при компиляции приложения.

Next.js 16.4 также включает множество обновлений компилятора, улучшающих его производительность и корректность. Команда Turbopack внесла изменения в механизм выделения памяти, благодаря которым React Compiler теперь потребляет на 30% меньше памяти, а время компиляции сократилось на 15%.

Чтобы включить React Compiler и использовать его Rust-версию, добавьте соответствующие настройки в конфигурацию Next.js:

import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  reactCompiler: true,
  experimental: {
    turbopackRustReactCompiler: true,
  },
};
 
export default nextConfig;

Подробнее в документации по Rust-версии React Compiler и в описании улучшений производительности компилятора.

Очистка дискового кеша

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

В Next.js 16.4 появился экспериментальный сборщик мусора, который удаляет такие неиспользуемые данные как из памяти, так и из дискового кеша. Это помогает снизить потребление ресурсов во время долгих dev-сессий. Он также умеет очищать устаревшие данные из предыдущих сессий, например, кеш для маршрутов, которые вы уже удалили.

Чтобы включить сборку мусора, добавьте настройку в конфигурацию Next.js:

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    turbopackGc: true,
  },
};

export default nextConfig;

Подробнее в документации по turbopackGc.

Ленивые динамические импорты

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

В Next.js 16.4 можно включить режим, при котором клиентские динамические импорты будут компилироваться только тогда, когда браузер действительно их запросит. Это уменьшает объём первоначальной компиляции для кода, который ещё не использовался — например, для библиотеки, загружаемой через import() после нажатия кнопки.

Чтобы включить ленивую компиляцию динамических импортов, добавьте настройку в конфигурацию Next.js:

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    turbopackLazyDynamicImports: true,
  },
};

export default nextConfig;

Некоторые импорты через next/dynamic по-прежнему компилируются заранее.

Подробнее в документации по turbopackLazyDynamicImports.

Worker Threads

Turbopack запускает такие инструменты, как Babel, PostCSS и webpack loaders, в отдельных процессах Node.js, которые взаимодействуют с ним через сокеты.

При использовании Worker Threads эти инструменты работают внутри одного процесса. Это позволяет избежать накладных расходов на отдельные процессы и обмен данными через сокеты и должно снизить потребление памяти и CPU как во время разработки, так и при сборке.

Чтобы включить Worker Threads, добавьте настройку в конфигурацию Next.js:

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    turbopackPluginRuntimeStrategy: 'workerThreads',
  },
};

export default nextConfig;

На Node.js 24.13.1 и новее Next.js пока откатывается обратно к дочерним процессам из-за бага в Node.js.

Подробнее в документации по turbopackPluginRuntimeStrategy.

Дополнительные корневые директории и поддержка глобальных virtual store

В Next.js 16.4 можно явно указывать дополнительные корневые директории, чтобы фреймворк мог работать с зависимостями, подключёнными через symlink и находящимися за пределами корня проекта. Это упрощает разработку локально связанных пакетов без необходимости расширять корень проекта и захватывать лишние директории.

Эта возможность также позволяет вручную интегрировать глобальные virtual store в pnpm, Bun, Nub и aube. Такие хранилища позволяют переиспользовать установленные зависимости между разными проектами и worktree, ускоряя установку пакетов. Автоматическую интеграцию планируют добавить в одном из будущих релизов.

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

import path from 'node:path';
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    turbopackAdditionalRoots: {
      linkedPackages: {
        path: path.join(__dirname, '../packages'),
      },
    },
  },
};

export default nextConfig;

Для глобального virtual store в pnpm добавьте как дополнительный root директорию, которую возвращает команда pnpm store path.

Подробнее в документации по additional roots.

Turbopack Bundle Analyzer

В этом релизе Turbopack Bundle Analyzer получил несколько крупных обновлений. Теперь он:

  • Показывает самые тяжёлые клиентские маршруты на новой главной странице со сводкой по маршрутам.

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

  • Автоматически создаёт снапшоты выполненных анализов и позволяет сравнивать бандлы по мере изменения приложения.

  • Отдельно выделяет модули, находящиеся на критическом пути рендеринга, и позволяет скрывать асинхронные зависимости во время анализа.

Кроме того, в Bundle Analyzer появился экспериментальный агентный Skill next-bundle-optimizer, который автоматически находит проблемные места, диагностирует их и помогает уменьшить объём JavaScript и других ресурсов, отправляемых приложением клиенту.

Чтобы использовать Skill:

  • Обновите приложение до Next.js 16.4.

  • Выполните npx skills add vercel/next.js --skill next-bundle-optimizer.

  • Запустите /next-bundle-optimizer в любом поддерживаемом AI-агенте.

Подробнее в документации по Turbopack Bundle Analyzer.

Обратная связь и сообщество

Надеемся, вам уже хочется попробовать Next.js 16.4!

Обновить приложение можно с помощью нового CLI для агентов:

npx next@canary upgrade --agent=latest

или вручную:

npm install next@latest

И обязательно делитесь обратной связью, она помогает формировать будущее Next.js:

Участники

Next.js это результат совместной работы тысяч разработчиков. Над этим релизом работали:

Огромное спасибо @kassens, @jamiboym, @6iu8a, @swarnava, @lukahartwig, @uaoa, @orzazade, @Samiislam851, @jarrensj, @sampoder, @martinfrancois, @leejpsd, @alangenfeld, @aryabyte21, @kostyniuk, @Stanzilla, @bmorros94, @ranger-ross, @styfle, @itsybitsci, @Amusac, @anujbolewar, @spirosikmd, @mezotv, @Xanaado, @marcoshernanz, @mlekhi, @dacgray, @molebox, @jgruica, @zeeshan56656, @lazerg, @hamidrezahanafi, @marceloboeira, @DavidIlie, @fireairforce, @QingHeSite, @niketchandivade, @biubiukam, @seanbeirnes, @0ldh, @fabian-hiller, @hardfist, @bryan-ferry, @gdborton, @hammadxcm, @syedsohailhussain1, @kelvinampofo, @koenpunt, @mayur9210, @Jashnavi25, @akselipalmer, @m-kawafuji, @Janpot и @kyamaz99 за помощь!