Headless CMS vs git-based blog: the ghost content SEO risk
Headless CMS vs git-based blog for SEO: headless setups risk invisible ghost content for weeks. A git-based static site avoids that failure by construction.
Headless CMS vs git-based blog for SEO: headless setups risk invisible ghost content for weeks. A git-based static site avoids that failure by construction.

A headless CMS and a git-based blog can both end up as clean HTML on a fast page. The difference that actually costs rankings shows up after you hit publish, not before. One architecture has a sync step between "content is live in the CMS" and "content is live on the internet." The other does not.
Every CMS eventually produces a page. The question that decides your SEO outcome is what has to happen, correctly, between an editor clicking publish and Googlebot or GPTBot actually being able to read that page as HTML.
In a headless setup (Contentful, Sanity, Storyblok, and similar tools), publishing writes to a content API. A separate frontend, usually Next.js or another framework, has to notice that write and rebuild or revalidate before the change is visible anywhere else. Vercel's own deploy hooks documentation spells out the mechanism plainly: "When a content change is published in the CMS, it has to tell Vercel that there is a new change and a deployment should get triggered." That "has to tell" is a webhook, a deploy hook URL, a piece of configuration that someone set up and that can silently stop working.
A git-based static site skips that step. Astro, Hugo, Jekyll, and Next.js in static export mode all compile every page to plain HTML at build time from a single source of truth, the repo itself. A merged pull request is both the publish event and the full content update. There is no separate CMS-to-frontend sync layer standing between the two, because there is no second system to sync with. We've run Astro against Next.js on exactly this build-time question before, and the CMS layer just adds one more moving part on top of whichever framework wins that comparison for you.
This isn't a reason headless is bad. It's a reason to know exactly where the failure mode lives before you pick an architecture for a content-led site. It's also the exact model our git-based AI blog writer writes into: no CMS, no separate publish step, just a pull request against your repo. If that's already how your blog ships, request early access and we'll show you how it looks against your own posts.
Ghost content is a page that's published and live inside the CMS, editors can see it, the CMS dashboard shows it as "live", but it isn't actually reachable as complete HTML on the public site yet. A crawler hitting the URL either gets the previous version or a shell that hasn't finished hydrating. The page exists. It just hasn't become visible to the internet.
sitepins.com's 2026 CMS-for-SEO analysis makes the underlying point directly: a headless setup like Contentful, Sanity Studio, or Storyblok decouples content from the frontend, so it's the frontend framework, whether it fetches and renders at request time or build time, that decides the SEO outcome, not the CMS itself. That rendering layer is exactly where ghost content gets introduced.
Two mechanisms create the gap, and both are common, not exotic misconfigurations.
The first is a missed or delayed webhook. If the deploy hook that's supposed to fire on publish doesn't fire, because of a dropped request, a misconfigured CMS environment, or a webhook someone forgot to re-point after a migration, the frontend never rebuilds. The content sits published in the CMS and stale on the site indefinitely, until someone notices or a scheduled rebuild happens to catch it.
The second is more subtle and harder to catch in review: an ISR (Incremental Static Regeneration) revalidation window that hasn't expired yet. Under Next.js ISR, a common pairing with headless CMS platforms, pages are served statically and only regenerated on a set interval or an on-demand webhook call. FocusReactive's 2026 headless CMS SEO analysis names the exact failure: "the first Googlebot crawl after a revalidation window expires gets the stale page." The fresh version only generates after that crawl triggers regeneration, on the next request. If your revalidation interval is an hour and Googlebot happens to crawl one minute after a correction goes live, it gets the wrong page, and depending on your crawl frequency, the correction might not reach the index for a while after that.
Neither of these is a bug in the CMS. They're a property of having a sync step at all. A headless architecture works exactly as designed and still ships stale content, because "designed" includes a webhook that has to fire and a cache that has to expire on schedule.
Google indexes JavaScript-heavy pages in two passes: an initial crawl and index on the raw HTML it receives, then a second pass once rendering resources are available and the page actually gets rendered. Google's Martin Splitt acknowledged back in an August 2019 Google Search Central Office Hours session, telling Onely: "I expect, eventually rendering, crawling and indexing will come closer together. We're not there yet, but I know the teams are looking into it." Years later, not there yet is still the operative phrase. On a large or resource-constrained site, the gap between the two waves still exists, and a thin pre-hydration shell means the first wave indexes an incomplete version of the page.
For AI answer-engine crawlers, there's no second wave at all. Vercel's engineering analysis of AI crawler traffic states it without qualification: "The results consistently show that none of the major AI crawlers currently render JavaScript." That covers OpenAI's GPTBot and OAI-SearchBot, Anthropic's ClaudeBot, Meta-ExternalAgent, and Perplexity's PerplexityBot. They fetch raw HTML once and move on. If your headless frontend ships a client-rendered shell that only becomes a full article after hydration, these crawlers see the shell, permanently, not the article. Google's Gemini is the one exception, since it runs on Googlebot's own infrastructure and inherits full JavaScript rendering, a capability that OpenAI's, Anthropic's, and Perplexity's crawlers simply don't have. The same client-side rendering gap that hides your article prose can hide your JSON-LD structured data too, a problem worth its own look at what schema actually helps with in AI Overviews.
The traffic at stake isn't trivial. Vercel's data puts GPTBot at roughly 569 million monthly fetches, Claude's crawler at around 370 million, AppleBot at about 314 million, and PerplexityBot at 24.4 million, combined AI crawler traffic runs close to 28% of Googlebot's own crawl volume. Claude's crawler even fetches JavaScript files on 23.84% of its requests without executing a single one of them, effort spent for nothing if that JS is where your content actually lives.
None of this makes headless the wrong choice for every content-led site. It's the right architecture when the content genuinely needs to go multiple places: the same product update feeding a website, a mobile app, and a marketing email, from one content model with typed fields for each variant. It's also the right choice when the people writing content aren't developers and shouldn't need a pull request to fix a typo. A visual editor with rich media handling, preview states, and role-based approval is a real editorial workflow advantage that a folder of Markdown files doesn't replicate on its own.
If your team already has editors who aren't comfortable with git, or your content has to serve more than one frontend, headless earns its complexity. The trade you're making is explicit: flexibility and non-technical access in exchange for a sync layer that has to be built and monitored correctly.
The cost side of that trade is ongoing, not one-time. techseoconsultant.com's audit of decoupled-architecture SEO failures lists the pattern plainly: "canonicals drift between environments, sitemaps stop reflecting what is actually indexable, or the initial HTML ships as a thin shell while content and meta tags appear only after hydration." None of these show up as an error in the CMS. They show up weeks later as a ranking drop that looks like a content problem and is actually a discoverability bug introduced when someone changed a caching config or forgot to re-point a webhook after an environment migration.
Keeping a headless setup airtight means someone owns webhook monitoring, revalidation interval tuning, canonical consistency across staging and production, and sitemap accuracy, as an ongoing engineering responsibility, not a launch checklist you complete once. Skip that ownership and the gap reopens quietly.
A git-based static site can't have the ghost content bug, structurally, because the step that would introduce it doesn't exist. The build that turns your Markdown into HTML is the same step that makes it public. There's no delivery API to poll, no cache to expire, no webhook to miss. If the build succeeds, the deployed page is complete HTML the instant it's live, which is exactly what both a first-pass Googlebot crawl and a non-rendering AI crawler need.
That correctness compounds through Core Web Vitals too. The May 2026 CrUX dataset (18,445,974 origins measured) shows only 55.9% of all origins pass all three Core Web Vitals thresholds, a slight decline from April, per digitalapplied.com's benchmark analysis. Pass rates split sharply by platform: November 2025 HTTP Archive data puts Duda at 84.87%, Webflow at 79% on desktop but only 67% on mobile, Shopify at 75.22%, Wix at 74.86%, Drupal at 63.27%, and WordPress at just 46.28%. The WordPress number is the interesting one: in a separate June 2025 CrUX snapshot, its INP pass rate alone is a strong 85.89%, comparable to Wix. WordPress isn't unresponsive, it's slow to load. Its failure is specifically LCP and server-side rendering time, which is precisely the layer a git-based static build removes by not having a server render anything at request time at all.
Build time itself isn't the bottleneck that decides this. For a blog-sized site, a few hundred Markdown posts, both Astro and Next.js statically generate the whole site in well under two minutes on typical CI, a point our Astro vs Next.js Core Web Vitals comparison walks through in more detail. "The git push is the deploy" isn't marketing shorthand. It's the literal build pipeline.
We tested this on our own blog. Pulling the raw HTML response for that Astro vs Next.js post, with no JavaScript executed, the actual article prose is already sitting in the markup: sentences like "Astro wins Core Web Vitals by default for a content-only blog" are readable in the first byte the server sends, not injected after hydration. That's the check worth running on any page you're relying on for SEO, headless or git-based: view source, not inspect element, and see if the words you wrote are actually there.
Structured data itself doesn't favor either architecture, both a headless frontend and a git-based static site can emit identical JSON-LD, since it's markup generated at render time, not a CMS feature. Google is direct that "there's also no special schema.org structured data that you need to add" to appear in AI Overviews or AI Mode, and Ahrefs's controlled test of 1,885 pages that added JSON-LD against 4,000 matched control pages found no meaningful citation lift from adding schema alone. What schema buys you is hygiene: correct rich results and clearer entity understanding, not an AI citation advantage. Our schema markup for AI Overviews breakdown covers exactly which structured data is worth shipping in 2026 and which is cargo-culted.
What does favor one architecture is the rendering question underneath the schema. If your headless frontend's JSON-LD is injected client-side alongside the rest of a hydrated page, a non-rendering AI crawler never sees it, same problem as the ghost content bug, one layer up. A git-based static build emits the JSON-LD into the same HTML response as the article body, so any crawler that can read the page at all reads the structured data too. The architecture decision from earlier in this post determines whether your schema investment is actually visible to the crawlers you built it for.
AI crawler traffic also rewards clean, stable URLs specifically, which a static build enforces at compile time rather than at runtime. Vercel's data found ChatGPT's crawler hitting 404 pages on 34.82% of its fetches and Claude's crawler on 34.16%, against just 8.22% for Googlebot. A site with URLs that shift, redirect chains, or slugs that change between a CMS preview and the published path burns a meaningful share of an AI crawler's limited attention on dead ends before it ever reaches your actual content.
The decision isn't headless versus git-based in the abstract. It's a question about who edits your content and how much engineering time you're willing to spend keeping a sync layer correct.
| Signal | Lean toward |
|---|---|
| Non-technical writers who need a visual editor and preview states | Headless |
| Same content ships to a website, app, and email from one model | Headless |
| Small technical team, blog is the only content channel | Git-based |
| Indexing correctness by default matters more than editor convenience | Git-based |
| You have engineering capacity to own webhook and revalidation monitoring | Headless is workable |
| You want zero moving parts between publish and live | Git-based |
| Content changes are infrequent and reviewed like code anyway | Git-based |
None of this is a verdict that headless CMS platforms are bad SEO. It's a tradeoff, and like most architecture decisions, it rewards being explicit about which side of it you're choosing rather than discovering the failure mode after a page has been silently stale for three weeks.
If your blog already lives in a git repo, that same merged-PR-is-the-publish-event property is what Lyra is built around: she opens a pull request against your repo, and the build that ships it is the same build that makes the post fully-formed, indexable HTML. No separate CMS sync step to monitor, because there isn't one to add.
A git-based blog has one publish event: a merged pull request. Lyra writes into that event instead of adding a new one to babysit.
FAQ
Ghost content is a page that is published and live in the CMS but not actually reachable as full HTML on the public site yet, because a rebuild webhook misfired, an ISR revalidation window has not expired, or the frontend is still serving a cached version. Search engines and AI crawlers see the old page, or nothing, until the sync layer catches up.
Not by itself. A headless CMS is a content store; the frontend that renders and caches that content determines the SEO outcome. The risk is architectural: a headless setup adds a sync step, webhook, revalidation, or on-demand rebuild, between publishing and indexing, and that step can fail silently. A git-based static site removes the step entirely.
Because the build that turns a post into live HTML is the same event that makes it public. There is no separate delivery API, cache layer, or webhook standing between the content store and the rendered page. If the build succeeds, the page is fully-formed HTML the moment it is deployed, which is what both Googlebot's first pass and non-rendering AI crawlers need.
No. None of the major AI answer-engine crawlers, OpenAI's GPTBot and OAI-SearchBot, Anthropic's ClaudeBot, Meta-ExternalAgent, Perplexity's PerplexityBot, or ByteDance's Bytespider, execute JavaScript. They fetch raw HTML and move on. Google's Gemini is the exception, since it runs on Googlebot's own rendering infrastructure.
It depends on who edits the blog and how many channels the content feeds. A headless CMS wins when non-technical writers need a visual editor or the same content ships to a website, app, and marketing emails. A git-based static site wins when the team is technical, the blog is the only channel, and indexing correctness by default matters more than editor convenience.
Built by the tool you're reading about
Lyra finds the topics worth ranking for, writes them in your repo's voice, fact-checks every claim, and opens a pull request scored and ready to merge. You review and hit merge. Want to see what she'd write for you? Tell us about your blog and the founder will walk through it with you.
Keep reading

AI blog writer cost compared against freelance rates, agency retainers, and in-house salaries at real posting volumes, plus a breakeven formula to run.

Bring your own API key and pay per token, or pay a flat SaaS markup. Real Claude pricing versus Jasper, Surfer, and Byword shows what each post costs.

How to choose an AI blog writer: a five-criteria buyer's checklist covering fact-checking, editorial control, brand voice, and BYOK cost transparency.