Я видел этот паттерн как минимум в пяти Next.js-кодбазах:
// app/sitemap.ts
export default function sitemap() {
return pages.map((page) => ({
url: `https://example.com${page.path}`,
lastModified: new Date(), // ← Баг
}))
}
При каждом билде каждая страница получает сегодняшнюю дату как lastModified. Деплоишь в понедельник — Google думает, что все 50 страниц изменились в понедельник. Деплоишь во вторник — Google думает, что все 50 страниц изменились во вторник.
Это не просто неправильно — это активно вредит твоему SEO.
Почему это важно
Google использует lastmod как сигнал для приоритета обхода. Когда ты сообщаешь Google, что страница была изменена, он приоритизирует её повторный обход. Если каждая страница заявляет об изменении при каждом деплое, Google понимает, что твои значения lastmod ненадёжны, и начинает их игнорировать.
Из документации Google: «Мы игнорируем значения <lastmod>, которые явно неточны (например, если все даты установлены на текущую дату).»
Как только Google перестаёт доверять твоему lastmod, ты теряешь возможность сигнализировать о реально изменившихся страницах. Настоящее обновление контента — новый пост в блоге, обновлённая страница с ценами — получает тот же приоритет обхода, что и всё остальное.
Правильный подход
lastmod должен отражать, когда контент конкретной страницы действительно изменился. Для разных типов страниц:
Статические страницы (about, contact, services)
Они меняются редко. Устанавливай lastmod на дату последнего редактирования как статическую строку:
{
url: 'https://example.com/about',
lastModified: '2026-06-15', // Последний раз, когда ты реально редактировал эту страницу
}
Или лучше: получай дату из git-истории файла:
import { execSync } from 'child_process'
function getLastModified(filePath: string): string {
const date = execSync(
`git log -1 --format=%cI -- ${filePath}`
).toString().trim()
return date || new Date().toISOString()
}
// В sitemap.ts
{
url: 'https://example.com/about',
lastModified: getLastModified('app/about/page.tsx'),
}
Это даёт реальную дату последнего коммита файла — точно и автоматически.
Посты в блоге
У постов в блоге есть поле date во фронтматтере. Используй его:
const posts = getAllPosts('ru')
const blogEntries = posts.map((post) => ({
url: `https://example.com/ru/blog/${post.slug}`,
lastModified: post.date, // Из фронтматтера
}))
Если обновляешь пост после первоначальной публикации, добавь поле lastUpdated во фронтматтер и используй его вместо date:
lastModified: post.lastUpdated || post.date,
Динамические страницы (e-commerce товары, пользовательский контент)
Для страниц, работающих с базой данных, храни временную метку updatedAt и используй её:
const products = await db.products.findMany({
select: { slug: true, updatedAt: true },
})
const productEntries = products.map((product) => ({
url: `https://example.com/products/${product.slug}`,
lastModified: product.updatedAt,
}))
Страницы, которые невозможно датировать
Для страниц, где ты действительно не знаешь, когда последний раз менялся контент: полностью опускай lastmod. Отсутствующий lastmod лучше, чем неправильный. Google будет использовать собственные данные обхода для определения свежести.
{
url: 'https://example.com/some-page',
// Нет lastModified — и это нормально
}
Полный паттерн sitemap
Вот паттерн sitemap, который я использую в клиентских проектах:
// app/sitemap.ts
import { getAllPosts } from '@/lib/blog'
export default function sitemap() {
const staticPages = [
{ url: 'https://example.com', lastModified: '2026-07-01' },
{ url: 'https://example.com/about', lastModified: '2026-06-15' },
{ url: 'https://example.com/services', lastModified: '2026-07-10' },
// Обновляй эти даты при редактировании страниц
]
const posts = getAllPosts('ru')
const blogPages = posts.map((post) => ({
url: `https://example.com/ru/blog/${post.slug}`,
lastModified: post.date,
}))
return [...staticPages, ...blogPages]
}
Просто. У каждой страницы точная дата. Никакого new Date() нигде.
Ловушка деплоя
Причина, по которой new Date() так распространён: это то, что напишешь, если думаешь «страница только что собрана, значит она только что изменилась». Но сборка и изменение — разные вещи.
Деплой пересобирает каждую страницу. Это не значит, что контент каждой страницы изменился. HTML может быть побайтово идентичен вчерашней сборке. lastmod должен отслеживать изменения контента, а не временные метки билда.
Как проверить
После деплоя получи свой sitemap и проверь даты:
curl -s https://yoursite.com/sitemap.xml | head -30
Если каждый <lastmod> показывает сегодняшнюю дату — у тебя баг. Если даты разные (одни старые, другие свежие) — всё правильно.
Я поймал именно этот баг в клиентском проекте, где sitemap возвращал HTML вместо XML. Баг с lastmod тоньше — sitemap работает, но просто врёт Google.
Однострочный фикс
Если сейчас используешь new Date() и нет времени на полное исправление: просто убери lastModified из записей, где у тебя нет точной даты.
// До (неправильно)
{ url: '...', lastModified: new Date() }
// После (правильно, если не знаешь реальную дату)
{ url: '...' }
Опустить lastmod лучше, чем врать. Google использует собственную историю обходов как запасной вариант, который точнее временной метки билда.
Хочешь, чтобы техническое SEO было сделано правильно с первого дня? Напиши мне — я нахожу эти тихие SEO-баги до того, как они съедят твой crawl budget.