БлогУслугиКарьера
Обсудить проект
БлогУслугиКарьераОбсудить проект
React / Next.js

Next.js 16: что нового и как использовать в production

Полный обзор Next.js 16: Turbopack по умолчанию, нативный next.config.ts, API after(), forbidden/unauthorized, улучшенный PPR. Миграция с 15.

Редакция Feature
Редакция Feature·
19 мар
·
14 мин
·
Next.js 16: что нового и как использовать в production

Почему Next.js 16 — важный релиз

Next.js 16 закрепляет все экспериментальные фичи, которые появились в версии 15, и делает их стабильными. Turbopack стал сборщиком по умолчанию, конфигурация получила нативную поддержку TypeScript, а новые API вроде after() и forbidden() упрощают типовые серверные сценарии. Если вы откладывали миграцию с 14-й версии — сейчас лучший момент.

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

Если вам нужна профессиональная React/Next.js разработка, наша команда работает с Next.js с ранних версий и уже мигрировала несколько крупных проектов на версию 16.

Turbopack — сборщик по умолчанию

Что изменилось

В Next.js 15 Turbopack был стабилен только для dev-режима и требовал флага --turbo. В 16-й версии Turbopack стал * сборщиком по умолчанию* — и для next dev, и для next build. Webpack больше не используется, если вы явно не переключитесь на него.

Ключевые цифры из бенчмарков Vercel:

Метрика Webpack Turbopack Ускорение
Холодный старт dev-сервера 8.2 сек 1.9 сек 4.3x
Fast Refresh (изменение компонента) 350 мс 85 мс 4.1x
Production build (средний проект) 62 сек 18 сек 3.4x
Обработка 10 000 модулей 45 сек 7 сек 6.4x

Как это выглядит

Никаких флагов больше не нужно — Turbopack работает из коробки:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

Если в проекте есть кастомные Webpack-плагины, которые ещё не совместимы с Turbopack, можно временно вернуться на Webpack:

{
  "scripts": {
    "dev": "next dev --webpack",
    "build": "next build --webpack"
  }
}

Конфигурация Turbopack

Turbopack поддерживает собственный блок настроек для кастомных лоадеров и алиасов:

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  turbopack: {
    rules: {
      "*.svg": {
        loaders: ["@svgr/webpack"],
        as: "*.js",
      },
    },
    resolveAlias: {
      underscore: "lodash",
    },
  },
};

export default nextConfig;

Обратите внимание: блок turbopack вынесен из experimental на верхний уровень конфигурации — это отражает его стабильный статус.

Нативный next.config.ts

Конец эры .js и .mjs

Next.js 16 нативно поддерживает конфигурацию в TypeScript. Больше не нужно использовать JSDoc-аннотации или сторонние обёртки:

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "export",
  trailingSlash: true,
  images: {
    unoptimized: true,
  },
};

export default nextConfig;

Файл обрабатывается напрямую — без предварительной компиляции в JS. Поддерживаются импорты из других .ts-файлов, что позволяет выносить сложную логику конфигурации в отдельные модули.

Приоритет файлов

Если в проекте есть несколько файлов конфигурации, Next.js выбирает по приоритету:

  1. next.config.ts (наивысший)
  2. next.config.mjs
  3. next.config.js

Рекомендуем мигрировать на .ts — вы получите автодополнение, проверку типов и защиту от опечаток в названиях опций.

API after() — код после ответа

Проблема

Типичная задача: после обработки запроса нужно выполнить побочные действия — записать аналитику, обновить кэш, отправить уведомление. Раньше для этого использовали waitUntil() (Vercel-специфичный) или фоновые задачи вручную.

Решение

after() — стабильный API для выполнения кода после того, как ответ отправлен клиенту. Он работает в Server Components, Server Actions, Route Handlers и Middleware:

// app/api/checkout/route.ts
import { after } from "next/server";

export async function POST(request: Request) {
  const order = await processOrder(request);

  // Этот код выполнится после отправки ответа клиенту
  after(async () => {
    await analytics.track("order_completed", { orderId: order.id });
    await emailService.sendConfirmation(order.email);
    await inventoryService.decrementStock(order.items);
  });

  return Response.json({ orderId: order.id, status: "success" });
}

Использование в Server Components

// app/product/[id]/page.tsx
import { after } from "next/server";

export default async function ProductPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;
  const product = await getProduct(id);

  // Записываем просмотр после отрисовки страницы
  after(async () => {
    await analytics.trackView("product", id);
  });

  return <ProductDetails product={product} />;
}

Ключевое преимущество: after() не задерживает Time to First Byte (TTFB). Клиент получает ответ сразу, а побочные задачи выполняются в фоне.

forbidden() и unauthorized()

Новые помощники для авторизации

Next.js 16 добавляет два новых помощника, аналогичных notFound():

import { forbidden, unauthorized } from "next/navigation";
  • unauthorized() → вызывает рендер файла 401.tsx (HTTP 401)
  • forbidden() → вызывает рендер файла 403.tsx (HTTP 403)

Пример использования

// app/admin/page.tsx
import { forbidden, unauthorized } from "next/navigation";
import { getSession } from "@/lib/auth";

export default async function AdminPage() {
  const session = await getSession();

  if (!session) {
    unauthorized(); // Пользователь не авторизован → 401.tsx
  }

  if (session.role !== "admin") {
    forbidden(); // Нет прав доступа → 403.tsx
  }

  return <AdminDashboard />;
}

Создание страниц ошибок

Добавьте файлы 401.tsx и 403.tsx в нужные сегменты:

// app/401.tsx
export default function UnauthorizedPage() {
  return (
    <div>
      <h1>Необходима авторизация</h1>
      <p>Войдите в аккаунт, чтобы получить доступ к этой странице.</p>
      <a href="/login">Войти</a>
    </div>
  );
}
// app/403.tsx
export default function ForbiddenPage() {
  return (
    <div>
      <h1>Доступ запрещён</h1>
      <p>У вас нет прав для просмотра этой страницы.</p>
    </div>
  );
}

Раньше для таких случаев приходилось выбрасывать исключения или редиректить вручную. Теперь это стандартная часть фреймворка.

Нужен современный веб-проект?

Разработаем на Next.js 16 с нуля или мигрируем существующий

Заказать разработку на Next.js

Partial Prerendering — стабильная версия

Что это

Partial Prerendering (PPR) позволяет одной странице быть частично статической и частично динамической. Статическая оболочка отдаётся мгновенно из CDN, а динамические части стримятся по мере готовности.

В Next.js 15 PPR был экспериментальным. В 16-й версии он стал стабильным и включается инкрементально — для отдельных маршрутов:

Как это работает

  1. При next build Next.js рендерит страницу и находит границы <Suspense>
  2. Статическая часть сохраняется как HTML-оболочка
  3. Динамические части заменяются fallback-заглушками
  4. При запросе пользователя сервер отдаёт статический HTML мгновенно
  5. Динамические части стримятся и заменяют заглушки
// app/product/[id]/page.tsx
import { Suspense } from "react";

export const experimental_ppr = true;

export default async function ProductPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;

  return (
    <main>
      {/* Статическая часть — рендерится при сборке */}
      <ProductInfo id={id} />

      {/* Динамические части — стримятся при каждом запросе */}
      <Suspense fallback={<ReviewsSkeleton />}>
        <ProductReviews id={id} />
      </Suspense>

      <Suspense fallback={<RelatedSkeleton />}>
        <RelatedProducts id={id} />
      </Suspense>
    </main>
  );
}

Включение PPR

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  experimental: {
    ppr: "incremental",
  },
};

export default nextConfig;

Затем отметьте маршруты, которые должны использовать PPR:

export const experimental_ppr = true;

PPR лучше всего подходит для страниц с комбинацией статического и динамического контента: каталоги товаров, дашборды, персонализированные лендинги. Подробнее об оптимизации производительности читайте в нашей статье Оптимизация Next.js: от 50 до 100 баллов PageSpeed.

Улучшения кэширования

Стабильный opt-in подход

В Next.js 15 кэширование fetch() стало opt-in вместо opt-out. В 16-й версии этот подход закреплён и расширен. Появились более удобные утилиты для управления кэшем:

import { unstable_cache } from "next/cache";

// Кэширование произвольных функций (не только fetch)
const getCachedProducts = unstable_cache(
  async (category: string) => {
    return await db.product.findMany({ where: { category } });
  },
  ["products"],
  { revalidate: 300, tags: ["products"] },
);

// Использование
const products = await getCachedProducts("electronics");

Тегированная ревалидация

Система тегов стала надёжнее и предсказуемее:

// Кэшируем с тегами
const product = await fetch(`https://api.example.com/products/${id}`, {
  next: { tags: [`product-${id}`, "products"] },
});

// Инвалидируем конкретный продукт
import { revalidateTag } from "next/cache";
revalidateTag(`product-${id}`);

// Или все продукты разом
revalidateTag("products");

Клиентский Router Cache

Поведение клиентского кэша маршрутов осталось opt-in, как в 15-й версии. Если нужно включить кэширование навигации:

// next.config.ts
const nextConfig: NextConfig = {
  experimental: {
    staleTimes: {
      dynamic: 30,
      static: 180,
    },
  },
};

Улучшения Server Actions

Безопасность и производительность

Server Actions в Next.js 16 стали ещё безопаснее. Фреймворк автоматически шифрует идентификаторы действий и создаёт уникальные эндпоинты при каждой сборке. Это предотвращает воспроизведение старых запросов после деплоя.

useActionState — стабильный API

Хук useActionState из React 19, который пришёл на смену useFormState, полностью стабилен:

"use client";

import { useActionState } from "react";
import { createPost } from "./actions";

export function CreatePostForm() {
  const [state, formAction, isPending] = useActionState(createPost, null);

  return (
    <form action={formAction}>
      <input name="title" placeholder="Заголовок поста" required />
      {state?.error && <p className="text-red-500">{state.error}</p>}
      <button type="submit" disabled={isPending}>
        {isPending ? "Создание..." : "Создать пост"}
      </button>
    </form>
  );
}

Улучшенная обработка ошибок

Server Actions интегрированы с Error Boundaries. Ошибки в серверных действиях корректно перехватываются ближайшим error.tsx:

// app/actions.ts
"use server";

import { revalidatePath } from "next/cache";

export async function createPost(formData: FormData) {
  const title = formData.get("title") as string;

  if (!title || title.length < 3) {
    return { error: "Заголовок должен быть не менее 3 символов" };
  }

  await db.post.create({ data: { title } });
  revalidatePath("/posts");
  return { success: true };
}

Руководство по миграции с Next.js 15 на 16

Шаг 1: Обновление зависимостей

npm install next@16 react@19 react-dom@19

React 19 был в Next.js 15, так что обновлять его версию не нужно — достаточно обновить сам Next.js.

Шаг 2: Миграция конфигурации на TypeScript

Переименуйте next.config.mjs (или .js) в next.config.ts:

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // ваша существующая конфигурация
};

export default nextConfig;

Если у вас были CommonJS-импорты (require), замените на ESM-импорты (import).

Шаг 3: Обновите блок turbopack

Если вы использовали experimental.turbo, перенесите его на верхний уровень:

// Было (Next.js 15)
const nextConfig: NextConfig = {
  experimental: {
    turbo: {
      rules: { ... }
    }
  }
};

// Стало (Next.js 16)
const nextConfig: NextConfig = {
  turbopack: {
    rules: { ... }
  }
};

Шаг 4: Проверьте совместимость Webpack-плагинов

Если в проекте были кастомные Webpack-конфигурации через webpack в next.config, проверьте их совместимость с Turbopack. Большинство популярных плагинов уже поддерживаются:

  • @svgr/webpack — поддерживается через turbopack.rules
  • CSS Modules — работают из коробки
  • Tailwind CSS — работает из коробки
  • sass — поддерживается нативно

Если какой-то плагин не совместим, временно используйте --webpack флаг.

Шаг 5: Используйте after() вместо кастомных решений

Если вы использовали waitUntil() или ручные фоновые задачи для пост-обработки запросов, замените на after():

// Было
export async function POST(request: Request) {
  const result = await processData(request);

  // Хак с waitUntil или Promise без await
  void sendAnalytics(result);

  return Response.json(result);
}

// Стало
import { after } from "next/server";

export async function POST(request: Request) {
  const result = await processData(request);

  after(async () => {
    await sendAnalytics(result);
  });

  return Response.json(result);
}

Обсудим ваш проект?

Оставьте контакты — перезвоним и обсудим задачу

Шаг 6: Тестирование

После обновления проверьте:

  • Сборка — next build теперь использует Turbopack, убедитесь что проект собирается без ошибок
  • Навигация — все переходы между страницами работают
  • Server Actions — формы обрабатываются корректно
  • Стили — CSS/Tailwind рендерятся правильно с Turbopack
  • Middleware — проверьте совместимость с новой версией

Советы по оптимизации для production

Используйте Server Components по умолчанию

Все компоненты в Next.js 16 по умолчанию серверные. Добавляйте 'use client' только когда компоненту нужны клиентские API: обработчики событий, useState, useEffect, браузерные API. Это минимизирует объём JavaScript на клиенте.

Стратегия кэширования

Составьте карту всех источников данных:

// Справочники — кэшируем надолго
const categories = await fetch(url, { next: { revalidate: 86400 } });

// Списки — кэшируем ненадолго
const products = await fetch(url, { next: { revalidate: 300 } });

// Персональные данные — без кэша
const cart = await fetch(url, { cache: "no-store" });

Мониторинг бандла

npm install -D @next/bundle-analyzer
// next.config.ts
import bundleAnalyzer from "@next/bundle-analyzer";

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true",
});

export default withBundleAnalyzer(nextConfig);

Статический экспорт для простых сайтов

Если проекту не нужен сервер (лендинги, блоги, корпоративные сайты), используйте статический экспорт:

const nextConfig: NextConfig = {
  output: "export",
  trailingSlash: true,
  images: { unoptimized: true },
};

Это генерирует чистый HTML/CSS/JS, который можно раздавать через Nginx или любой CDN. Именно такой подход мы используем для наших собственных проектов.

Заключение

Next.js 16 — зрелый релиз, который закрепляет всё лучшее из 15-й версии:

  • Turbopack по умолчанию — ускоряет и dev, и build в 3-6 раз
  • Нативный next.config.ts — типизированная конфигурация без обходных путей
  • after() — стандартный способ выполнять код после ответа
  • forbidden() / unauthorized() — чистая обработка 401/403 ошибок
  • Стабильный PPR — статика + динамика на одной странице
  • Улучшенное кэширование — предсказуемое и управляемое

Миграция с 15-й версии минимальна — главное проверить совместимость с Turbopack. Новые проекты рекомендуем начинать сразу на Next.js 16.

Если вам нужна помощь с миграцией или разработкой нового проекта на Next.js, обращайтесь — у нас есть опыт работы с крупными production-проектами на этом фреймворке.

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

Обсудим ваш проект?

Оставьте контакты — перезвоним и обсудим задачу

Содержание
  • Почему Next.js 16 — важный релиз
  • Turbopack — сборщик по умолчанию
  • Нативный next.config.ts
  • API after() — код после ответа
  • forbidden() и unauthorized()
  • Partial Prerendering — стабильная версия
  • Улучшения кэширования
  • Улучшения Server Actions
  • Руководство по миграции с Next.js 15 на 16
  • Советы по оптимизации для production
  • Заключение
Поделиться:

Похожие статьи

React Server Actions: практический гайд для продакшена
React / Next.js

React Server Actions: практический гайд для продакшена

13 мин
Server Components vs Client Components: когда что использовать
React / Next.js

Server Components vs Client Components: когда что использовать

12 мин
Оптимизация Next.js: от 50 до 100 баллов PageSpeed за 1 день
React / Next.js

Оптимизация Next.js: от 50 до 100 баллов PageSpeed за 1 день

14 мин
Feature IT

Feature IT — платформа по обучению программированию и разработке цифровых продуктов. Мы создаём современные веб-решения для бизнеса и обучаем этому других!

Политика конфиденциальностиПользовательское соглашение

О компании

  • Блог
  • Карьера

Услуги разработки

  • Разработка сайтов под ключ
  • Веб-приложения на React/Next.js
  • Telegram-боты для бизнеса
  • Mini Apps (Telegram, VK)
  • SEO-оптимизированные сайты
  • Автоматизация бизнес-процессов
  • Поддержка и развитие IT-продуктов

Обучение

  • Курс Python с нуля
  • Алгоритмы и структуры данных
  • Паттерны проектирования
  • Подготовка к собеседованиям в IT
  • Практика на реальных проектах

Инструменты

  • Генератор UTM-меток
  • Счётчик символов