Полное руководство по настройке SEO на Next.js
15 апреля 2026 г.
Next.js — это фреймворк React с мощной поддержкой SEO из коробки, но для достижения максимальной видимости в поисковых системах требуется дополнительная настройка. В этом руководстве ты узнаешь, как правильно управлять мета-тегами, структурированными данными, динамическими маршрутами, sitemap и производительностью, чтобы твой Next.js проект получал максимум органического трафика.
Управление метаданными в Next.js
С выходом Next.js 13 появились два подхода к работе с метаданными: классический Pages Router и новый App Router. Выбор зависит от версии и архитектуры твоего проекта.
Метаданные в App Router
В App Router используется экспорт статического или динамического объекта metadata из файла layout.tsx или page.tsx. Это самый современный и рекомендуемый способ.
// app/layout.tsx
export const metadata = {
title: {
default: 'Мой сайт',
template: '%s | Мой сайт'
},
description: 'Описание сайта для поисковых систем',
keywords: 'nextjs, seo, react',
robots: 'index, follow',
viewport: 'width=device-width, initial-scale=1'
}
export default function RootLayout({ children }) {
return (
<html lang="ru">
<body>{children}</body>
</html>
)
}
Объект metadata поддерживает все основные теги: title, description, robots, canonical, alternates, openGraph, twitter и другие. Шаблон %s в title.template автоматически подставляет заголовок дочерней страницы.
Метаданные в Pages Router
Если ты используешь Pages Router, метаданные добавляются через компонент Head из next/head.
// pages/index.js
import Head from 'next/head'
export default function Home() {
return (
<>
<Head>
<title>Главная страница</title>
<meta name="description" content="Описание главной страницы" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://example.com/" />
</Head>
{/* контент */}
</>
)
}
Для динамического управления метатегами на каждой странице используй next/head внутри компонента страницы. В отличие от App Router, здесь нет автоматического наследования — нужно повторять общие теги на каждой странице или создать компонент-обёртку.
Динамические метаданные
В реальных проектах заголовки и описания часто зависят от данных — например, от содержимого статьи или товара. В App Router для этого используется функция generateMetadata.
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPostBySlug(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [post.coverImage]
},
alternates: {
canonical: `https://example.com/blog/${params.slug}`
}
}
}
Функция выполняется на сервере при каждом запросе (или во время сборки для статических страниц). Это позволяет генерировать уникальные метатеги для каждой страницы на основе внешних данных.
В Pages Router динамика реализуется через getServerSideProps или getStaticProps с последующей передачей данных в Head.
Open Graph и Twitter Cards
Open Graph (OG) отвечает за то, как твой сайт выглядит при публикации в соцсетях (Facebook, VK, LinkedIn, Telegram). Twitter использует отдельный набор тегов, но поддерживает и OG.
В App Router добавь поле openGraph в объект metadata:
export const metadata = {
title: 'Заголовок статьи',
openGraph: {
title: 'Заголовок для соцсетей',
description: 'Краткое описание для превью',
url: 'https://example.com/article',
siteName: 'Мой сайт',
images: [
{
url: 'https://example.com/og-image.jpg',
width: 1200,
height: 630,
alt: 'Превью статьи'
}
],
type: 'article',
publishedTime: '2025-04-15T00:00:00Z',
authors: ['Автор']
},
twitter: {
card: 'summary_large_image',
title: 'Заголовок для Twitter',
description: 'Описание для Twitter',
images: ['https://example.com/twitter-image.jpg']
}
}
Рекомендуемый размер изображения для OG — 1200×630 пикселей, формат JPEG или PNG. Без указания OG-тегов соцсети будут использовать случайные элементы страницы, что часто выглядит непрезентабельно.
Структурированные данные (JSON-LD)
JSON-LD — это формат разметки, помогающий поисковым системам лучше понимать содержимое страницы: статьи, товары, рецепты, отзывы, организации. Next.js рекомендует встраивать JSON-LD через компонент Script с type="application/ld+json" и стратегией beforeInteractive или afterInteractive.
Пример для статьи (Article Schema):
// app/blog/[slug]/page.tsx
import Script from 'next/script'
export default function BlogPost({ post }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
description: post.excerpt,
image: post.coverImage,
datePublished: post.date,
author: {
'@type': 'Person',
name: post.author
},
publisher: {
'@type': 'Organization',
name: 'Мой сайт',
logo: {
'@type': 'ImageObject',
url: 'https://example.com/logo.png'
}
}
}
return (
<>
<Script
id="article-jsonld"
type="application/ld+json"
strategy="afterInteractive"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* контент статьи */}
</>
)
}
Используй валидатор структурированных данных от Google (Rich Results Test), чтобы убедиться в корректности разметки. Ошибки в JSON-LD не нарушат работу страницы, но могут помешать поисковым системам использовать расширенные сниппеты.
Генерация sitemap и robots.txt
Карта сайта (sitemap) помогает поисковым роботам находить все страницы, особенно если сайт имеет динамическую структуру. В Next.js App Router sitemap генерируется автоматически через специальный файл.
Создай app/sitemap.ts:
// app/sitemap.ts
import { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://example.com'
// Получи список всех статей из CMS или БД
const posts = await getAllPosts()
const postUrls = posts.map((post) => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly',
priority: 0.8
}))
return [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1.0
},
...postUrls
]
}
Файл robots.txt создаётся в app/robots.ts:
// app/robots.ts
import { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: ['/admin/', '/api/']
},
sitemap: 'https://example.com/sitemap.xml'
}
}
В Pages Router используются сторонние библиотеки, например next-sitemap, которая генерирует статические файлы во время сборки.
Оптимизация производительности для SEO
С 2021 года Google использует Core Web Vitals (LCP, INP, CLS) как фактор ранжирования. Next.js предоставляет несколько инструментов для автоматической оптимизации.
1. Встроенная оптимизация изображений через компонент next/image автоматически ресайзит, сжимает и использует современные форматы (WebP, AVIF).
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/photo.jpg"
width={1200}
height={630}
alt="Описание изображения"
priority // для LCP-изображений
/>
)
}
2. Динамический импорт для отложенной загрузки некритичных компонентов:
const HeavyComponent = dynamic(() => import('@/components/Heavy'), {
loading: () => <p>Загрузка...</p>,
ssr: false
})
3. Предзагрузка ссылок через компонент Link с пропом prefetch (включен по умолчанию в production).
4. Минимизация размера страницы — Next.js автоматически расщепляет код (code splitting) и добавляет только необходимый JavaScript для каждой страницы.
Используй Lighthouse в Chrome DevTools для проверки Core Web Vitals на реальных страницах. Даже при идеальном SEO медленный сайт будет проигрывать конкурентам.
Типичные ошибки и как их избежать
Ошибка 1: Дублирование метатегов — в App Router не смешивай экспорт metadata с компонентом Head из next/head. Используй только один подход.
Ошибка 2: Отсутствие канонических URL — если один контент доступен по нескольким адресам (например, с трекерными параметрами), укажи canonical в метаданных, чтобы избежать дублей в индексе.
Ошибка 3: Клиентская загрузка контента — если важный текст подгружается через useEffect или fetch на клиенте, поисковый робот может его не увидеть. Используй серверные компоненты или getServerSideProps/generateStaticParams.
Ошибка 4: Игнорирование мобильных устройств — Google индексирует в первую очередь мобильную версию. Убедись, что сайт корректно отображается на экранах от 320px, используй адаптивный дизайн.
Ошибка 5: Отсутствие страницы 404 — создай кастомную страницу not-found.tsx в App Router или 404.js в Pages Router. Это улучшает пользовательский опыт и сигнализирует поисковым системам о битых ссылках.
После внедрения всех настроек проверь результат в Google Search Console — отправь sitemap, посмотри на покрытие индексации и ошибки робота. SEO — это непрерывный процесс, требующий мониторинга и адаптации под изменения алгоритмов.
Что почитать дальше
Дополнительные материалы из архива, которые могут быть полезны после этой статьи.
Полное руководство по CI/CD для Next.js в GitLab: от базовой настройки до продакшн-пайплайна
Подробное руководство по настройке CI/CD для Next.js приложений с GitLab CI. Разбираем каждый этап пайплайна, кэширован…
Читать далее
Самые популярные вопросы по Next.js на собеседовании: разбор с примерами
Собрали 30+ самых частых вопросов по Next.js для подготовки к собеседованию. Разбираем App Router, Server Components, р…
Читать далее
Next.js для начинающих: полное руководство по фреймворку React
Освойте Next.js с нуля: полное руководство для начинающих разработчиков. Узнайте, как создавать производительные и SEO-…
Читать далее