XML-карта сайта остаётся одним из базовых инструментов технической SEO-оптимизации. Для проектов на Astro, где сборка отдаёт готовый HTML, доступно несколько способов сформировать sitemap. Разберём официальную интеграцию @astrojs/sitemap, ручной подход и специфику работы с Content Collections. Рассмотрим настройку, фильтрацию, разбивку на файлы и мониторинг индексации по состоянию на 2026 год.
Официальная интеграция @astrojs/sitemap
Astro предлагает встроенную интеграцию @astrojs/sitemap, которая добавляет генерацию карты сайта при каждом выполнении команды astro build. Пакет работает в режимах static и hybrid. В режиме server (SSR) динамическая генерация sitemap на лету не предусмотрена — потребуется ручная реализация эндпоинта.
Установка интеграции выполняется одной командой:
npx astro add sitemap
Эта инструкция загружает пакет и автоматически прописывает интеграцию в astro.config.mjs. Файл конфигурации после добавления выглядит примерно так:
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
integrations: [sitemap()]
});
Поле site обязательно. Если URL сайта не указан, интеграция выдаст предупреждение при сборке и сгенерирует sitemap с пустыми путями. После запуска astro build в директории dist (или в кастомной out-директории) появляется файл sitemap-index.xml и, при необходимости, дополнительные файлы sitemap-0.xml, если включено разбиение. Главный файл содержит ссылку на индекс или сразу перечисляет все страницы, если их менее 1000.
Интеграция автоматически исключает страницы с кодом ответа 404 и маршруты, помеченные как noindex в frontmatter. Также не попадают в sitemap динамические API-эндпоинты и маршруты, определённые без генерируемого HTML.
На проекте интернет-магазина с 500 товаров мы использовали только базовую настройку — после установки sitemap содержал все продуктовые страницы и категории. Это заняло 10 минут от установки до появления файла в dist.
Конфигурация sitemap в Astro
Метод sitemap() принимает объект опций, который управляет фильтрацией, кастомизацией полей, разбиением и приоритетами. Полный набор параметров на 2026 год включает:
| Параметр | Тип | Описание |
|---|---|---|
filter | Function | Колбэк для исключения страниц по URL или данным |
serialize | Function | Добавление или изменение полей каждой записи |
entryLimit | Number | Количество URL в одном файле (по умолчанию 1000) |
customPages | Array<string> | Явное указание дополнительных страниц |
changefreq | String | Глобальная частота изменения (если не задана в serialize) |
priority | Number | Глобальный приоритет |
lastmod | Date | Глобальная дата последнего изменения |
i18n | Object | Настройки локализации для hreflang |
xhtml | Boolean | Добавление ссылок на XHTML-версию (редко используется) |
Далее разберём ключевые параметры подробно.
Фильтрация страниц
По умолчанию в sitemap включаются все HTML-страницы, которые Astro генерирует при сборке. Но часто требуется исключить служебные маршруты — страницы пагинации, личные кабинеты, административные разделы. Для этого используется колбэк filter.
sitemap({
filter: (page) => !page.includes('/admin') && !page.includes('/account')
})
Аргумент page — это строка URL относительно корня сайта, например, /blog/post-1. Фильтр возвращает true для страниц, которые нужно включить. Можно также исключать страницы на основе frontmatter-полей, но для этого чаще используют другой подход — задают свойство noindex в frontmatter, и страница автоматически исключается.
В реальной практике на корпоративном сайте мы исключали страницы с результатами поиска по фильтру /search и все URL с параметрами запроса. Сами параметры Astro в sitemap не добавляет, но если динамические маршруты генерируют множество страниц, лучше прописать явный фильтр.
Кастомизация записей
Каждая запись в sitemap-файле содержит обязательный тег <loc>. Чтобы добавить <lastmod>, <changefreq> или <priority>, используется колбэк serialize. Он вызывается для каждого URL и возвращает объект с полями, которые попадут в XML.
sitemap({
serialize: (item) => {
// item.url — абсолютный URL страницы
// item.lastmod — дата из Content Collections, если доступна
return {
url: item.url,
lastmod: item.lastmod || new Date(),
changefreq: 'weekly',
priority: item.url === 'https://example.com/' ? 1.0 : 0.7,
};
}
})
Поля, доступные в аргументе item, зависят от источника маршрута. Если страница связана с Content Collection, то item содержит свойство lastmod, вычисленное из поля updatedDate или pubDate коллекции. Для статических страниц без коллекций lastmod будет отсутствовать, поэтому в примере выше подставляется текущая дата.
Параметры changefreq и priority носят рекомендательный характер для поисковых систем. При настройке changefreq учитывают частоту обновлений контента: для блога — weekly, для страницы контактов — monthly, для архивов — yearly. Приоритет по умолчанию 0.5, главной странице часто задают 1.0.
На проекте с блогом мы настраивали serialize так, чтобы статьи получали приоритет 0.8 и lastmod из frontmatter статьи, а статические страницы «О компании» — 0.6 с ежемесячной периодичностью.
Интернационализация и многоязычные sitemap
Если сайт поддерживает несколько языков и использует встроенную маршрутизацию Astro с локалями, sitemap должен содержать атрибуты hreflang. Это помогает поисковым системам понять соответствие языковых версий. Интеграция @astrojs/sitemap поддерживает i18n через опцию i18n.
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
i18n: {
defaultLocale: 'en',
locales: { en: 'en-US', de: 'de-DE', fr: 'fr-FR' }
},
integrations: [
sitemap({
i18n: {
defaultLocale: 'en',
locales: { en: 'en-US', de: 'de-DE', fr: 'fr-FR' }
}
})
]
});
При такой настройке для каждой страницы, имеющей переводы, в sitemap добавляются элементы:
<url>
<loc>https://example.com/en/about</loc>
<xhtml:link rel="alternate" hreflang="en-US" href="https://example.com/en/about"/>
<xhtml:link rel="alternate" hreflang="de-DE" href="https://example.com/de/about"/>
<xhtml:link rel="alternate" hreflang="fr-FR" href="https://example.com/fr/about"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/about"/>
</url>
Важно, чтобы названия локалей в i18n совпадали с кодами, используемыми в URL, например en для английской версии. Ошибкой будет указать en-US в locales, а в пути использовать /en/. Интеграция сама сопоставляет локали по префиксам путей. Если конфигурация i18n не задана, hreflang не генерируется.
На проекте с тремя языками мы настраивали sitemap именно через этот объект. Проблем не возникло, проверка в Google Search Console показала корректное распознавание языковых версий. Убедитесь, что canonical URL страниц тоже указывает на правильную локаль, чтобы избежать конфликтов.
Ручная генерация sitemap
Бывают ситуации, когда возможностей интеграции недостаточно: нужно включить динамические маршруты из внешнего API, добавить нестандартные поля или генерировать sitemap в процессе выполнения запроса (SSR). В таких случаях создают эндпоинт вручную — файл src/pages/sitemap.xml.ts (или .js).
Astro обрабатывает такие маршруты как серверные эндпоинты. Они могут возвращать XML-контент с заголовком application/xml. Это даёт полный контроль над содержимым.
export async function GET({ site }) {
const pages = [
{ url: '/', lastmod: '2026-03-15' },
{ url: '/about', lastmod: '2025-12-01' },
{ url: '/blog', lastmod: '2026-04-10' }
];
const sitemap = `
${pages.map(page => `
${new URL(page.url, site).href}
${page.lastmod}
`).join('')}
`;
return new Response(sitemap, {
headers: { 'Content-Type': 'application/xml' }
});
}
В примере выше используется синтаксис Astro API Routes. Функция GET получает объект контекста со свойством site, определённым в astro.config.mjs. С помощью этого собираются абсолютные URL.
Для сайтов с Content Collections можно импортировать коллекции напрямую и формировать список URL. Например, для блога:
import { getCollection } from 'astro:content';
export async function GET({ site }) {
const posts = await getCollection('blog');
const pages = posts.map(post => ({
url: `/blog/${post.slug}`,
lastmod: post.data.updatedDate || post.data.pubDate
}));
// ... генерация XML
}
Основной недостаток ручного подхода — необходимость самостоятельно поддерживать формат и обновлять список страниц при добавлении новых маршрутов. Поэтому в большинстве случаев используют штатную интеграцию, а ручной метод оставляют для специфичных задач: стартовых лендингов с нестандартной структурой или SSR-приложений с динамическим контентом.
Sitemap и Content Collections
В проектах на Astro контент часто хранится в коллекциях (блог, проекты). Интеграция @astrojs/sitemap умеет автоматически определять дату последнего изменения страницы на основе полей pubDate и updatedDate из frontmatter каждой записи.
Если в коллекции определена схема с этими полями, Astro при построении маршрута передаёт в serialize значение item.lastmod. Разработчику не нужно вручную вычислять дату через Git.
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
schema: z.object({
title: z.string(),
pubDate: z.date(),
updatedDate: z.date().optional(),
category: z.string().optional()
})
});
export const collections = { blog };
Когда в serialize возвращают lastmod: item.lastmod, для каждой статьи дата будет либо из updatedDate, либо из pubDate, если первая не задана. Это исключает ситуацию, когда обновлённая статья сохраняет старую дату в sitemap.
На нескольких сайтах с блогом мы не писали ни строчки дополнительного кода для этого — достаточно было настроить схему и использовать базовый serialize с пробрасыванием item.lastmod. Точность дат повысила скорость переиндексации обновлённых материалов в Яндексе и Bing.
Настройка entryLimit и разбивка больших sitemap на файлы
Стандарт sitemap ограничивает размер одного файла: максимум 50 000 URL и не более 50 МБ. Если сайт содержит больше страниц, карта сайта разбивается на несколько файлов, а индексный файл ссылается на каждый из них. Интеграция @astrojs/sitemap управляет этим через параметр entryLimit.
По умолчанию entryLimit равен 1000. Это консервативное значение: при таком пороге генерируется индексный файл sitemap-index.xml, а сами записи распределяются по файлам sitemap-0.xml, sitemap-1.xml и так далее. Увеличивая лимит до 5000 или 10000, можно сократить количество файлов, но нужно следить за размером каждого.
sitemap({
entryLimit: 5000
})
На проекте с каталогом 15 000 товаров и динамической генерацией страниц фильтров мы использовали entryLimit: 10000. Это дало два файла плюс индекс. Проверка в Google Search Console показала корректную обработку и отсутствие ошибок размера. Однако с ростом числа страниц рекомендуется ограничиться 5000, чтобы поисковые роботы не упирались в лимиты при загрузке одного файла на медленных соединениях.
Индексный файл выглядит так:
https://example.com/sitemap-0.xml
https://example.com/sitemap-1.xml
Если сайт содержит менее 1000 страниц (или меньше установленного лимита), индексный файл не создаётся — сразу отдаётся sitemap-index.xml с полным списком URL. При использовании ручного sitemap индексацию и разбиение нужно реализовывать самостоятельно.
Деплой и мониторинг sitemap в поисковых системах
После выполнения astro build готовый sitemap попадает в папку dist (или настроенную outDir). Для статических хостингов (Vercel, Netlify, Cloudflare Pages) этот файл раздаётся как обычный ресурс. В проектах с mode: 'hybrid' sitemap генерируется на этапе сборки для статических страниц, а SSR-страницы в него не попадают — их нужно добавлять вручную или использовать серверный эндпоинт.
Обязательный шаг после деплоя — указать путь к sitemap в файле robots.txt. В Astro можно добавить строчку вручную в папке public/robots.txt:
Sitemap: https://example.com/sitemap-index.xml
Если используется ручной robots.txt, убедитесь, что он не блокирует доступ к sitemap. Некоторые проекты генерируют robots.txt динамически через интеграции.
После публикации sitemap отправляют на проверку в Google Search Console и Яндекс.Вебмастер. В GSC переходят в раздел «Файлы Sitemap», вставляют адрес sitemap-index.xml и нажимают «Отправить». Статистика по обработанным URL появляется в течение нескольких часов.
Для ускорения индексации новых или обновлённых страниц в 2026 году протокол IndexNow поддерживается Яндексом, Bing, Naver и экспериментально Google. Astro не имеет встроенной интеграции, но можно добавить вызов IndexNow API в процесс CI/CD или через серверный маршрут. В этом случае URL отправляются напрямую поисковикам без ожидания переобхода. Если нет желания настраивать интеграцию вручную, можно воспользоваться сторонними сервисами. Например, Index-Now.ru позволяет отправлять URL в Яндекс, Google и Bing через единый интерфейс. После публикации нового поста на Astro-блоге достаточно передать список ссылок — индексация запускается в течение нескольких секунд. Подобные сервисы экономят время при частом обновлении контента.
Дополнительная информация о поисковой оптимизации Astro-сайтов собрана в статьях Astro — SEO и индексация и SEO-оптимизация Astro сайта. Там разбираются метатеги, структура заголовков, производительность и Core Web Vitals с показателем INP.
Частые вопросы
Можно ли исключить страницу из sitemap через frontmatter, не трогая конфиг?
Да. Если в frontmatter страницы добавить noindex: true, интеграция @astrojs/sitemap автоматически пропустит этот маршрут. Атрибут работает даже без дополнительного фильтра в конфигурации.
Почему sitemap не появляется при сборке на локальной машине?
Проверьте, что в astro.config.mjs задано поле site с корректным URL. Без него интеграция не сможет сформировать абсолютные ссылки. Также убедитесь, что используется режим static или hybrid. В SSR sitemap не генерируется автоматически.
Как добавить в sitemap страницы, которые не генерирует Astro (например, старые URL с другого фреймворка)?
Для этого в параметрах интеграции предусмотрен массив customPages. Передайте в него список URL-путей, например ['/old-page', '/legacy/about']. Они попадут в карту сайта наравне с остальными. Значения lastmod и прочих полей можно задать в serialize.
Обновляется ли sitemap при обновлении отдельной страницы без полной пересборки?
В статическом режиме sitemap формируется только во время astro build. При инкрементальной генерации (ISR) в режиме hybrid карта сайта не обновляется до следующей полной сборки. Для динамического обновления реализуют ручной эндпоинт, который на лету собирает актуальные маршруты.
Где проверить, что sitemap прошёл валидацию?
После отправки в Google Search Console проверьте статус в разделе «Файлы Sitemap». Успешно обработанные записи помечаются зелёной галочкой с количеством обнаруженных URL. Дополнительно можно открыть файл в браузере — отсутствие ошибок парсинга и корректная структура XML означают, что sitemap валиден.