Sitemap для seo портала nextjs решает одну задачу: показать поисковику все страницы, которые он иначе не найдет. Если у вас 50, 500 или 6000 динамических страниц, статический sitemap.xml устаревает через день после деплоя. Ниже — рабочая связка app/s…
10+ лет в маркетинге, 300+ клиентских проектов: сайты, реклама, боты. Создатель GoBanana (228K+ пользователей, 11.6 млн ₽ выручки) и VibeCoderz. Делаю AI-продукты сам через Claude Code, Cursor, Windsurf и консультирую тех, кто хочет так же.
Об авторе →Claude Code: новый CLI-агент от Anthropic
Anthropic выпустила Claude Code — терминальный AI-агент для разработчиков. Инструмент работает прямо в командной строке и умеет писать, редактировать и запускать код.
Zcode AI: Полный гид по визуальному интерфейсу для Claude Code и AI-агентов
Узнайте, как использовать Zcode для управления Claude Code, Gemini и Codex в едином GUI. Настройка провайдеров, MCP-серверов и визуальный вайбкодинг.
YouTube-канал с монетизацией из любой точки мира: Пошаговый гайд 2026
Инструкция по созданию YouTube-канала: обход блокировок SMS, настройка расширенных функций через виртуальные номера и правила безопасности для монетизации.
Windsurf Code Maps: Как глубоко понимать архитектуру проекта перед написанием кода
Полный гайд по Windsurf Code Maps, модели Sway 1.5 и Sway Grep. Узнайте, как визуализировать архитектуру кода и ускорить разработку в 13 раз.
Vk Fast Cash Strategy
Аудитория ВКонтакте — это те же люди, что и в Instagram, но 'социальный контракт' площадки другой. Если Instagram — это 'дорогой ресторан' с демонстрацией успеха, то VK — это 'душевная шашлычная'. Здесь не работает глянцевый 'успешный успех
Sitemap для seo портала nextjs решает одну задачу: показать поисковику все страницы, которые он иначе не найдет. Если у вас 50, 500 или 6000 динамических страниц, статический sitemap.xml устаревает через день после деплоя. Ниже — рабочая связка app/sitemap.ts и app/robots.ts, которая обновляется сама при каждой сборке, плюс что делать, когда страниц становится больше 50 000.
Next.js App Router генерирует sitemap.xml из файла app/sitemap.ts без единой строчки XML. Для сайтов с 50 000+ страниц нужна функция generateSitemaps и sitemap-индекс. В статье — рабочий код, сравнение со встроенным способом и npm-пакетом next-sitemap, и связка с robots.ts.
Статический sitemap.xml перестает работать в тот момент, когда на сайте появляется хотя бы один раздел с растущим числом страниц: блог, каталог, теги.
Google индексирует страницы двумя путями: находит их по внутренним ссылкам или узнает из sitemap. Для программного SEO с тысячами страниц — единственный надежный путь. Портал с блогом, каталогом инструментов и тегами каждый день добавляет новые URL, и файл руками никто не обновляет.
У нас в VibeCoderz так и было. Каталог, блог, теги, категории — все это растет без остановки, и вручную вписывать новый URL в sitemap.xml после каждой публикации никто бы не стал. Решение простое: sitemap собирается кодом из тех же данных, из которых собираются страницы.
Максим: «Портал VibeCoderz мы с командой собрали за неделю тремя скриптами голосом в Claude Code. Уже в первый месяц — 4 303 посетителя и 36 000 показов в Google. Без нормального sitemap эти цифры просто не случились бы, страницы физически не индексируются без него.»

Файл app/sitemap.ts экспортирует функцию, которая возвращает массив объектов с url и lastModified. Next.js сам превращает его в валидный sitemap.xml на роуте /sitemap.xml.
Для маленького статичного сайта достаточно вернуть фиксированный массив ссылок. Для портала с базой данных или CMS функция становится асинхронной: делает fetch, забирает список опубликованных материалов и на его основе строит sitemap.
// app/sitemap.ts
import type { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getAllPublishedPosts() // ваш способ получить данные
const staticRoutes: MetadataRoute.Sitemap = [
{ url: 'https://vibecoderz.ru', lastModified: new Date(), changeFrequency: 'daily', priority: 1 },
{ url: 'https://vibecoderz.ru/ide', lastModified: new Date(), changeFrequency: 'daily', priority: 0.9 },
]
const postRoutes: MetadataRoute.Sitemap = posts.map((post) => ({
url: `https://vibecoderz.ru/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly',
priority: 0.8,
}))
return [...staticRoutes, ...postRoutes]
}Ключевой момент — запрос к данным должен идти без кэша (cache: 'no-store' в fetch или прямой запрос к базе), иначе sitemap будет строиться на старых данных сборки. И да, lastModified — не декорация: Google использует эту дату, чтобы понять, стоит ли перечитывать страницу заново.
Если функция закэшируется на этапе билда, новые публикации просто не попадут в sitemap до следующего деплоя. На портале с ежедневными публикациями это означает потерю индексации на несколько дней для каждой новой статьи. Проверить легко: опубликовать материал, подождать деплой, открыть /sitemap.xml и найти его там глазами.

У Google жесткий лимит: не более 50 000 URL в одном файле sitemap. Next.js решает это функцией generateSitemaps, которая автоматически создает несколько файлов и sitemap-индекс.
Google откажется читать файл размером больше 50 000 ссылок или 50 МБ, согласно официальной документации Next.js по generateSitemaps. Для портала с 6 000+ материалов это пока не критично, но при росте каталога до десятков тысяч страниц лимит наступит быстро — особенно если добавить программное SEO по тегам и нишам.
Функция generateSitemaps возвращает массив идентификаторов, а сам sitemap.ts получает id и отдает нужный кусок данных:
// app/blog/sitemap.ts
import type { MetadataRoute } from 'next'
export async function generateSitemaps() {
const totalPosts = await countPublishedPosts()
const sitemapsNeeded = Math.ceil(totalPosts / 50000)
return Array.from({ length: sitemapsNeeded }, (_, id) => ({ id }))
}
export default async function sitemap({ id }: { id: number }): Promise<MetadataRoute.Sitemap> {
const start = id * 50000
const posts = await getPostsRange(start, start + 50000)
return posts.map((post) => ({
url: `https://vibecoderz.ru/blog/${post.slug}`,
lastModified: post.updatedAt,
}))
}Каждый сгенерированный файл доступен по адресу вида /blog/sitemap/0.xml, /blog/sitemap/1.xml и так далее. Next.js сам собирает из них общий индекс — вручную писать XML-обертку не нужно.

Встроенный sitemap.ts подходит для большинства порталов и не требует зависимостей. Пакет next-sitemap нужен, если хочется тонко настраивать robots.txt, исключения и лимиты в одном конфиге.
Оба варианта закрывают задачу генерации sitemap, но по-разному. Встроенный способ — часть фреймворка, без установки пакетов, но робот robots.txt придется писать отдельно через app/robots.ts. Пакет next-sitemap — сторонняя библиотека, которая по данным npm-страницы проекта с версии 2.x сама делает индекс-sitemap и позволяет задать sitemapSize для разбивки на файлы.
| Критерий | app/sitemap.ts (встроенный) | next-sitemap (npm) |
|---|---|---|
| Установка | не нужна, часть Next.js | npm install next-sitemap |
| Разбивка на файлы при 50 000+ URL | через generateSitemaps | через опцию sitemapSize |
| robots.txt | отдельный app/robots.ts | генерируется тем же конфигом |
| Исключение путей | вручную в коде | через exclude в конфиге |
| Настройка под 6 500+ страниц портала | требует своего кода для пагинации | готовое решение из коробки |
| Порог входа | ниже, меньше файлов | выше, свой конфиг-файл |
Для нового портала на 1000-3000 страниц хватает встроенного способа. Если у вас несколько источников данных (каталог + блог + теги + агенты) и нужен единый robots.txt с явными правилами по разделам — next-sitemap экономит время на самописной логике объединения.

Файл app/robots.ts генерирует robots.txt автоматически и обязан содержать прямую ссылку на sitemap.xml, иначе поисковик может не найти файл сам.
Без строки Sitemap: в robots.txt краулер полагается на ручную отправку в Search Console или Яндекс.Вебмастер — а это на день-два медленнее, чем автоматическое обнаружение при каждом заходе робота на сайт.
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: ['/dashboard/', '/settings/', '/api/'],
},
sitemap: 'https://vibecoderz.ru/sitemap.xml',
}
}Частая ошибка на порталах с личным кабинетом и админкой — забыть закрыть /dashboard/ и /api/ в disallow. Робот честно обходит эти разделы, тратит краулинговый бюджет на страницы без ценности для поиска, а нужные материалы индексируются медленнее.

Правильно настроенный sitemap с корректным lastModified сокращает время между публикацией и появлением страницы в поиске — Google в первую очередь перечитывает страницы, где дата изменилась.
Программное SEO без карты сайта — это страницы, которые физически не попадают в поиск, потому что робот о них не узнает. На портале с сотнями страниц по нишам и тегам (у VibeCoderz — 297 ниш в каталоге агентов) внутренние ссылки просто не успевают охватить все URL, и sitemap остается единственным полным списком для краулера.
Проверить, что sitemap реально работает, просто: зайти в Google Search Console → Индексирование → Файлы Sitemap, добавить https://vibecoderz.ru/sitemap.xml и посмотреть статус обработки. Если статус «Не удалось получить» — сначала проверить, что файл открывается в браузере без ошибки 500, а потом уже разбираться дальше.

Нужен ли sitemap.xml маленькому сайту на 10-15 страниц?
Формально нет — робот найдет все страницы по внутренним ссылкам за пару обходов. Но файл ничего не стоит в реализации через app/sitemap.ts, а Google Search Console требует его для полноценной статистики индексации.
Как часто Next.js пересобирает sitemap.xml?
При каждой сборке (build) и при каждом запросе, если функция помечена как динамическая через cache: 'no-store' в fetch-запросах внутри нее. На Vercel и Railway пересборка обычно привязана к деплою.
Что будет, если в sitemap попадет несуществующая страница?
Google попробует ее обойти, получит 404 и со временем перестанет доверять файлу чуть больше обычного. Разовая ошибка не критична, но регулярный мусор в sitemap снижает частоту обхода остальных страниц.
Можно ли исключить страницы личного кабинета из sitemap?
Да, и нужно — эти страницы не должны там быть в принципе. Их закрывают через disallow в robots.ts, а в sitemap.ts просто не добавляют такие URL в возвращаемый массив.
Сколько времени занимает переход со статического sitemap на динамический?
На портале среднего размера — час-полтора: создать app/sitemap.ts, подключить источник данных, проверить вывод на /sitemap.xml. Основное время уходит на выбор, откуда брать список URL, если данные разбросаны по нескольким источникам.
next-sitemap работает с App Router или только с Pages Router?
Работает с обоими: пакет поддерживает route.ts из App Router через getServerSideSitemap и legacy-методы для Pages Router.
Как проверить, что sitemap реально читается Google?
Через Google Search Console: раздел Индексирование → Sitemap, добавить URL файла и посмотреть статус и число обнаруженных страниц.
Sitemap и robots.txt — это входная точка индексации, а не гарантия попадания в топ. Дальше решают структура каталога, скорость страниц и внутренняя перелинковка. Если разбираетесь, какой AI IDE или инструмент подойдет под вашу задачу пока настраиваете техническую часть портала, загляните в каталог AI-инструментов — там собраны обзоры с ценами и сравнениями.
Если нужна консультация по SEO-архитектуре портала на Next.js — пишите Максиму в Telegram.
Обновлено: март 2026.