Monitor404

404 и редиректы в Next.js

В App Router страницу 404 задаёт файл app/not-found.tsx, а функция notFound() вызывает её из серверного кода. Редиректы настраивают в redirects() файла next.config.js (permanent: true даёт статус 308) или в middleware.

Обновлено 11 октября 2026 г.

Страница 404 в App Router

Создайте app/not-found.tsx. Next.js покажет его для любого адреса, которому не соответствует маршрут, и для случаев, когда вы вызвали notFound(). Страница отдаётся со статусом 404.

app/not-found.tsx
import Link from "next/link";

export default function NotFound() {
  return (
    <main>
      <h1>Страница не найдена</h1>
      <p>Возможно, адрес изменился. Вернитесь на главную или воспользуйтесь поиском.</p>
      <Link href="/">На главную</Link>
    </main>
  );
}

Файл not-found.tsx можно положить и во вложенную папку маршрута — он будет действовать внутри этого сегмента.

notFound() для динамических страниц

app/blog/[slug]/page.tsx
import { notFound } from "next/navigation";

export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const post = await getPost(slug);

  if (!post) {
    notFound(); // прерывает рендер и показывает ближайший not-found.tsx
  }

  return <article>{post.title}</article>;
}

Для страниц, у которых список адресов известен заранее, добавьте export const dynamicParams = false;: тогда любой параметр вне generateStaticParams вернёт 404. Следите за стримингом: если ответ уже начал отправляться (например, из-за loading.tsx), заголовки ушли, и статус 404 не гарантирован — в документации Next.js для таких случаев описана вставка noindex. Проверяйте реальный ответ в проверке HTTP-статуса.

Pages Router

В проектах на pages/ создайте pages/404.js (или 404.tsx). Он генерируется статически при сборке, поэтому getServerSideProps в нём недоступен. Для динамических страниц верните { notFound: true } из getStaticProps или getServerSideProps. Страница 500 настраивается через pages/500.js.

pages/blog/[slug].tsx
export async function getServerSideProps({ params }) {
  const post = await getPost(params.slug);
  if (!post) {
    return { notFound: true };
  }
  return { props: { post } };
}

Редиректы в next.config.js

next.config.js
module.exports = {
  async redirects() {
    return [
      // 308 (постоянный)
      { source: "/old-page", destination: "/new-page", permanent: true },
      // сохраняем хвост пути
      { source: "/blog/:slug", destination: "/articles/:slug", permanent: true },
      { source: "/docs/:path*", destination: "/help/:path*", permanent: true },
      // 307 (временный)
      { source: "/promo", destination: "/sale", permanent: false },
      // конкретный код вместо permanent
      { source: "/legacy", destination: "/modern", statusCode: 301 },
    ];
  },
};
  • permanent: true отвечает кодом 308, permanent: false — 307. Оба сохраняют HTTP-метод запроса. Для поисковых систем 308 — такой же постоянный редирект, как 301, см. /http/308.
  • Если нужен именно 301 или 302, используйте statusCode. Одновременно с permanent его указывать нельзя.
  • Редиректы из next.config.js проверяются до файловой системы и до middleware.
  • В режиме output: "export" (статический экспорт) redirects() не работает — редиректы придётся настраивать на хостинге, например в nginx.

Middleware

Когда правила зависят от cookie, заголовков или хранятся во внешнем списке, используйте middleware. В новых версиях Next.js (16 и выше) файл middleware.ts переименован в proxy.ts — уточните в документации вашей версии.

middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

const redirects: Record<string, string> = {
  "/old-page": "/new-page",
  "/old-catalog": "/catalog",
};

export function middleware(request: NextRequest) {
  const target = redirects[request.nextUrl.pathname];
  if (target) {
    return NextResponse.redirect(new URL(target, request.url), 301);
  }
}

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

В серверных компонентах для редиректов есть redirect() (временный, по умолчанию 307) и permanentRedirect() (308) из next/navigation. Большие таблицы редиректов удобнее генерировать: генератор редиректов.

Частые ошибки

  • Страница-«ловушка» [...slug] рисует текст «не найдено», но не вызывает notFound() — статус остаётся 200.
  • redirect() вместо permanentRedirect() при переезде: временный редирект вместо постоянного.
  • Перенаправление всех 404 на главную в middleware — это soft 404.
  • Matcher middleware захватывает _next/static и картинки — лишняя нагрузка и поломка статики.
  • Конфликт trailingSlash и редиректов со слешем: цепочки и циклы.

Как найти 404 в Next.js

  • Логи платформы (Vercel, Node-сервер, nginx перед приложением) и отчёты Вебмастера и Search Console.
  • Проверка битых ссылок для отдельных страниц сайта.
  • Трекер на странице not-found — фиксирует фактические переходы посетителей.

Подключение Monitor404 к Next.js

Добавьте скрипт в app/not-found.tsx через next/script:

app/not-found.tsx
import Script from "next/script";

export default function NotFound() {
  return (
    <main>
      <h1>Страница не найдена</h1>
      <Script
        src="https://collect.monitor404.ru/collect/ВАШ_ТОКЕН/script.js"
        strategy="afterInteractive"
      />
    </main>
  );
}

Для Pages Router положите тот же Script в pages/404.js. Чтобы ловить ошибки на всех страницах, подключите скрипт с ?mode=auto в корневом layout.tsx. Если вам важно знать реальный HTTP-статус, отправляйте события с сервера через API Monitor404 с HMAC-подписью.

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

Как сделать страницу 404 в Next.js?

В App Router создайте app/not-found.tsx, в Pages Router — pages/404.js. Для конкретных страниц вызывайте notFound() из next/navigation (App Router) или возвращайте { notFound: true } из getStaticProps / getServerSideProps.

Какой код у редиректа с permanent: true в Next.js?

308, а для permanent: false — 307. Если нужен 301 или 302, укажите statusCode вместо permanent.

Как сделать редирект в Next.js?

Для статических правил — redirects() в next.config.js; для динамических — middleware с NextResponse.redirect(); в серверных компонентах — redirect() или permanentRedirect().

Почему страница not-found в Next.js отдаёт 200?

Возможные причины: кастомная catch-all страница не вызывает notFound(), ответ уже начал стримиться, либо статус подменяет прокси или CDN. Проверьте ответ в проверке HTTP-статуса.

Читайте также