The lastmod trap: why honesty matters in XML sitemaps
Your XML sitemap includes a lastmod date for every URL, and Google uses that signal to prioritize recrawling. But here's the catch: Google ignores lastmod when it lies. We'll walk you through how to keep lastmod honest: a Technical SEO guide for developers that actually moves the needle on crawl efficiency and indexing speed.
Most teams stumble into this problem gradually. An engineer sets every URL's lastmod to today's date. The product team updates a single field in their CMS. A migration touches all records without changing content. Before long, Google learns that your lastmod signal is noise, and you've squandered a tool that could be driving intelligent recrawl decisions.
Update lastmod only on meaningful content changes
The core principle is straightforward: lastmod should reflect when the content itself actually changed, not when the record was touched in your database. A meaningful change is something that affects what a visitor or search engine sees on the rendered page.
Let's say you run an e-commerce platform. A product listing has a title, description, price, images, and reviews. When a customer leaves a new review, should lastmod update? Not necessarily. When someone corrects a typo in the product description? Yes. When inventory changes from 100 to 99 units? That's a judgement call, but probably not in most contexts.
The practical rule: if a change would make you want Google to re-index that page soon, it deserves a lastmod bump. If the change is internal (a database migration, a schema update that doesn't affect output, a timestamp column that auto-updates), it doesn't.
Here's a common pattern in a Node.js / NestJS service:
// Bad: updates lastmod on every save
async updateProduct(id: string, data: Partial<Product>) {
return this.db.products.update(
{ id },
{ ...data, updatedAt: new Date() }
);
}
// Better: only bump lastmod for content changes
async updateProduct(id: string, data: Partial<Product>) {
const contentFields = ['title', 'description', 'price', 'images'];
const hasContentChange = contentFields.some(field => field in data);
const updatePayload = { ...data };
if (hasContentChange) {
updatePayload.lastmod = new Date();
}
return this.db.products.update({ id }, updatePayload);
}
This approach ensures lastmod moves only when it should. Your sitemap becomes a genuine signal of when pages changed meaningfully.
Never set every URL to today's date
Setting lastmod to today's date for all URLs is one of the most common SEO mistakes we see. It typically happens during a migration, a replatforming, or when someone misunderstands the purpose of lastmod as a "freshness" metric.
When Google crawls your sitemap and sees that every single URL has today's date, it learns one thing: your lastmod values are unreliable. From that point forward, Google deprioritizes the lastmod signal. You've burned credibility on a signal that could otherwise help you.
Consider a travel site that migrates from one platform to another. During the migration, an engineer writes a script:
-- DO NOT DO THIS
UPDATE pages
SET lastmod = NOW()
WHERE 1=1;
This touches 500,000 URLs. Google fetches the sitemap. Every URL shows today's date. Google thinks the entire site changed today. It crawls more aggressively for a few days, finds that nothing actually changed, and then learns that lastmod is a liar. The team loses weeks of trust-building.
The correct approach during migration is to preserve lastmod from your old system, or to leave it blank for pages that you genuinely haven't touched:
-- Better: preserve original lastmod
UPDATE pages
SET lastmod = COALESCE(lastmod, created_at)
WHERE lastmod IS NULL;
-- Or leave it empty if you don't have accurate historical data
UPDATE pages
SET lastmod = NULL
WHERE lastmod IS NULL;
Empty lastmod is honest. Google will crawl based on other signals like your crawl frequency history. Setting it to a false date is worse than omitting it entirely.
Accurate dates help recrawl prioritization
When lastmod is honest, Google uses it to make intelligent decisions about recrawl frequency. A page that changes daily gets recrawled more often. A page that rarely changes gets recrawled less often. This is smart resource allocation on Google's side.
From your perspective, accurate lastmod dates mean:
- High-traffic pages with frequent updates get fresher indexes faster.
- Archive or historical content that never changes stops consuming crawl budget.
- You signal which sections of your site are alive and actively maintained.
Let's look at a real scenario: a SaaS documentation site. Your API reference docs change whenever you ship a new endpoint. Your "About Us" page changes once a year. Your blog posts are archived and never updated.
If you set lastmod accurately, Google learns to recrawl your API docs weekly, your About page quarterly, and your old blog posts maybe twice a year. Your crawl budget is spent where it matters. If you set every page to today's date, Google treats all three categories the same—and eventually stops trusting the signal.
The impact compounds over time. A site with accurate lastmod and consistent update patterns can reduce crawl latency for important pages by 30–50% compared to a site with dishonest or missing lastmod values.
Drive it from your updatedAt column
The cleanest implementation is to derive lastmod directly from a single, authoritative column in your database. This removes ambiguity and makes the logic maintainable.
Most teams have an updatedAt timestamp that tracks when a record last changed. The challenge is that this column may include changes that don't affect the rendered page. The solution is to use a separate column specifically for content updates, or to filter your update logic carefully.
Here's a PostgreSQL example for a blogging platform:
-- Add a column that tracks content-relevant updates
ALTER TABLE posts ADD COLUMN lastmod TIMESTAMP;
-- Populate it for the first time
UPDATE posts SET lastmod = created_at WHERE lastmod IS NULL;
-- In your application, update lastmod only on content changes
CREATE OR REPLACE FUNCTION update_post(
p_id UUID,
p_title TEXT,
p_body TEXT
) RETURNS void AS $$
BEGIN
UPDATE posts
SET
title = p_title,
body = p_body,
lastmod = NOW(),
updated_at = NOW()
WHERE id = p_id;
END;
$$ LANGUAGE plpgsql;
Then in your sitemap generation, you simply query lastmod directly:
async generateSitemap() {
const posts = await this.db.posts.find({}, {
id: 1,
slug: 1,
lastmod: 1
});
const urls = posts.map(post => ({
loc: `https://example.com/blog/${post.slug}`,
lastmod: post.lastmod?.toISOString().split('T')[0]
}));
return this.buildSitemapXml(urls);
}
This approach is simple, auditable, and honest. When you run a report on your sitemap, you can immediately spot patterns: "Our product pages update on average every 3 days" or "Blog posts are never updated after publication." These patterns should match reality.
Common mistakes
Setting lastmod to now() on every deployment: If you deploy your site once a day, don't update lastmod for pages that didn't change. Your deployment frequency and your content update frequency are different things.
Updating lastmod when a related table changes: If a user leaves a comment on a blog post, the post record might have its updatedAt bumped by your ORM. Don't automatically set lastmod to that timestamp. Consider whether the change is visible to visitors first.
Mixing lastmod and freshness: Freshness (how recently content was published) is different from modification date. A news article published 6 months ago that was never edited should keep its original lastmod, not show today's date to appear "fresh."
Omitting lastmod entirely to avoid the responsibility: Some teams remove lastmod from their sitemaps to avoid getting it wrong. This is playing defense. Instead, invest 15 minutes to implement it properly and you gain a real edge.
Key takeaways
- lastmod is a signal Google uses to prioritize recrawling; dishonest values destroy that signal.
- Only update lastmod when content changes in a way that affects the rendered page.
- Never bulk-update all URLs to today's date, even during migrations.
- Maintain a separate lastmod column (or function) that tracks genuine content changes, not schema updates or metadata shifts.
- Audit your sitemap periodically to ensure lastmod patterns match your actual update frequency.
- Accurate lastmod helps you spend crawl budget efficiently and get important pages indexed faster.






Comments
Loading comments…