Назад в блог

Настройка SEO для сайта на Next

R
relaxdev
10.07.2026 430 просмотров 0 English

SEO для Next.js на RelaxDev — полный гайд

Всё, что нужно сделать, чтобы сайт попал в поисковики. Специфика Next.js App Router: robots и sitemap задаются TypeScript-файлами в папке app/, файлы подтверждения лежат в public/.


1. robots.txt

Создайте src/app/robots.ts — Next.js сам отдаст его по адресу /robots.txt:

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/app/robots.ts

import type { MetadataRoute } from 'next';



export default function robots(): MetadataRoute.Robots {

  return {

    rules: [

      {

        userAgent: '*',

        allow: '/',

        disallow: ['/api/', '/dashboard/', '/profile/', '/admin/', '/login/', '/auth/'],

      },

    ],

    sitemap: 'https://ваш-домен.ru/sitemap.xml',

  };

}

Проверка: откройте https://ваш-домен.ru/robots.txt — должен открыться текст со списком правил.


2. sitemap.xml

Создайте src/app/sitemap.ts:

TypeScript
1
2
3
4
5
6
7
8
9
10
11
// src/app/sitemap.ts

import type { MetadataRoute } from 'next';



export const dynamic = 'force-dynamic';



export default function sitemap(): MetadataRoute.Sitemap {

  return [

    { url: 'https://ваш-домен.ru', lastModified: new Date(), changeFrequency: 'weekly', priority: 1 },

    { url: 'https://ваш-домен.ru/about', lastModified: new Date(), changeFrequency: 'monthly', priority: 0.8 },

  ];

}

С динамическим контентом из базы (Prisma):

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import type { MetadataRoute } from 'next';

import { prisma } from '@/lib/prisma';



export const dynamic = 'force-dynamic';



export default async function sitemap(): Promise<MetadataRoute.Sitemap> {

  const baseUrl = 'https://ваш-домен.ru';



  const posts = await prisma.post.findMany({

    where: { published: true },

    select: { slug: true, updatedAt: true },

  });



  return [

    { url: baseUrl, lastModified: new Date(), changeFrequency: 'weekly', priority: 1 },

    { url: `${baseUrl}/about`, changeFrequency: 'monthly', priority: 0.8 },

    ...posts.map((p) => ({

      url: `${baseUrl}/blog/${p.slug}`,

      lastModified: p.updatedAt,

      changeFrequency: 'weekly' as const,

      priority: 0.7,

    })),

  ];

}

force-dynamic нужен, чтобы sitemap не собирался во время сборки: тогда Next.js не пойдёт в базу на этапе build.

Проверка: откройте https://ваш-домен.ru/sitemap.xml — должен открыться XML со списком страниц.


3. Закрыть служебные страницы от индексации

Страницы с авторизацией и личными данными нельзя пускать в поисковики. В App Router целый раздел закрывается одной строкой в layout.tsx — все вложенные страницы получат noindex:

TypeScript
1
2
3
4
5
6
// src/app/(dashboard)/layout.tsx

import type { Metadata } from 'next';



export const metadata: Metadata = {

  robots: { index: false, follow: false },

};

Это закрывает /dashboard, /profile, /settings и всё, что внутри.

Для отдельной страницы — то же самое в её page.tsx.

Проверить, что страница закрыта: в браузере Ctrl+U → найдите <meta name="robots" content="noindex">. Или Google Search Console → «Проверка URL».

На RelaxDev технический адрес проекта проект.relaxdev.ru и адреса превью уже отдаются с noindex — дублей вашего сайта в выдаче они не создают.


4. Название сайта в выдаче

Над заголовком результата Google показывает название сайта. Если сайт его не сообщил, Google подставляет домен — а кириллический домен в виде xn--…. Название задаётся разметкой WebSite на главной и og:site_name:

TSX
1
2
3
4
5
// src/app/layout.tsx

export const metadata: Metadata = {

  metadataBase: new URL('https://ваш-домен.ru'),

  openGraph: { siteName: 'Название сайта' },

};
TSX
1
2
3
4
5
6
7
8
9
10
11
12
13
// src/app/page.tsx — внутри разметки главной

<script

  type="application/ld+json"

  dangerouslySetInnerHTML={{

    __html: JSON.stringify({

      '@context': 'https://schema.org',

      '@type': 'WebSite',

      name: 'Название сайта',

      alternateName: 'ваш-домен.ru',

      url: 'https://ваш-домен.ru/',

    }),

  }}

/>

url должен совпадать с адресом главной в canonical. Google подхватит название при следующем обходе главной.


5. Подтверждение сайта

Самый простой способ в Next.js — метатеги через metadata, без файлов:

TypeScript
1
2
3
4
5
6
7
// src/app/layout.tsx

export const metadata: Metadata = {

  verification: {

    google: 'код-из-search-console',

    yandex: 'код-из-вебмастера',

  },

};

Если удобнее файлами — в Google Search Console и Яндекс Вебмастере выберите метод «HTML-файл», скачайте файлы и положите в public/:

CODE
1
2
3
public/

  google123abc456def.html     ← Google

  yandex_12345abcdef.html     ← Яндекс

Файлы из public/ доступны по корневому адресу автоматически: после деплоя https://ваш-домен.ru/google123abc456def.html откроется сразу. Закоммитьте, задеплойте и нажмите «Подтвердить» в панели каждого поисковика.


6. Яндекс Метрика

Счётчик — это не только аналитика: по опыту, с ним Яндекс находит и обходит новые страницы быстрее.

TSX
1
2
3
4
5
6
7
8
9
10
11
12
13
// src/app/layout.tsx

import Script from 'next/script';



// Внутри <body>:

<Script id="yandex-metrika" strategy="lazyOnload">

  {`(function(m,e,t,r,i,k,a){

    m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};

    m[i].l=1*new Date();

    k=e.createElement(t),a=e.getElementsByTagName(t)[0];

    k.async=1;k.src=r;a.parentNode.insertBefore(k,a)

  })(window,document,"script","https://mc.yandex.ru/metrika/tag.js","ym");

  ym(XXXXXXXX,"init",{ clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true });`}

</Script>

Где XXXXXXXX — номер счётчика из metrika.yandex.ru. lazyOnload грузит счётчик после загрузки страницы и не отнимает баллы у PageSpeed. Не забудьте упомянуть Метрику в политике cookie.


7. Отправить sitemap в поисковики

Без этого поисковики могут неделями не находить новые страницы.

  • Google Search Console: Индексирование → Файлы Sitemap → добавить https://ваш-домен.ru/sitemap.xml → «Отправить».
  • Яндекс Вебмастер: Индексирование → Файлы Sitemap → добавить https://ваш-домен.ru/sitemap.xml.

8. Кириллический домен (.рф и другие)

Домен кухниостровский.рф в DNS и браузерах хранится как xn--b1albebcsjatkdjj4a.xn--p1ai — это один и тот же адрес. Что важно для SEO:

  • Одна форма адреса везде: в metadataBase, canonical, sitemap, robots и внутренних ссылках. Punycode (xn--…) понимают все роботы без исключения.
  • Название сайта в выдаче — обязательно разметка WebSite из раздела 4. Без неё Google покажет над заголовком xn--….
  • Яндекс показывает кириллические домены нормально. В Вебмастере есть «Регистр имени сайта»: можно задать вид КухниОстровский.рф.
  • Ссылка, скопированная из выдачи или браузера, приходит в punycode — она рабочая, это та же страница.
  • В панели RelaxDev домен можно вводить кириллицей: хранится он в punycode, показывается кириллицей, записи у регистратора те же.

Подробнее про записи, www и редиректы — в статье «Домены и DNS на RelaxDev».


Чек-лист

  • https://ваш-домен.ru/robots.txt открывается
  • https://ваш-домен.ru/sitemap.xml открывается с нужными страницами
  • Закрытые разделы (/dashboard/, /admin/) имеют robots: { index: false }
  • На главной есть разметка WebSite с названием сайта
  • Сайт подтверждён в Google Search Console и Яндекс Вебмастере
  • Счётчик Метрики установлен
  • Sitemap отправлен в обе панели
  • Для домена выбран один вариант — с www или без — второй перенаправляется на него

Сроки: обычно Google — от нескольких дней до недели, Яндекс — несколько дней.

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

Вопросы — пишите в комментарии 👇

Комментарии (0)

Ответить без регистрации

Изображения, PDF, TXT • Ctrl+V для скриншота • до 5 файлов, 10 MB
Пока нет комментариев. Будьте первым!