Vibe Code a Blog With a CMS (That Google Can Actually Read)

Build a blog with AI — static generation, a CMS your writers can use, and the SEO fundamentals AI skips every single time.

C
CodeIllusion Team
#vibe-coding #blog #cms #seo #tutorial
Vibe Code a Blog With a CMS (That Google Can Actually Read)

A blog is a strong AI project — conventional structure, verifiable by looking, no meaningful security surface if you’re the only author.

It’s also the project where AI’s blind spot is most costly, because a blog exists to be found, and everything that makes it findable is invisible on the page.

Pick Your Content Source First

This decision shapes everything else.

Markdown in the repo — simplest and fastest. Posts are files, version controlled, no database, no CMS costs. Right answer if the writers are comfortable with Git.

A headless CMS — Sanity, Payload, or Contentful. Necessary when non-technical people need to publish without touching a repo.

Database-backed with your own editor — avoid this. Building a decent editing experience is far more work than it appears, and the result is always worse than an off-the-shelf one.

This guide uses markdown. Swap the source if you need a CMS; everything else holds.

The Build

Astro with TypeScript and Tailwind. A blog using content collections with markdown files.

Frontmatter schema: title, description, pubDate, updatedDate optional, category, tags array, heroImage optional, author, draft boolean.

Routes: / for the post index paginated at 12 per page, /[slug]/ for posts, /category/[category]/ and /tag/[tag]/ for filtering.

Statically generate everything at build time. Exclude drafts from production builds.

Astro is a good fit here specifically because it ships zero JavaScript by default, which makes blogs fast without effort.

The SEO Layer — Ask For All Of It

This is the entire point of the project and none of it will be there unless you name it.

Add complete SEO to every post page:

  • Title tag under 60 characters, meta description under 155
  • Self-referencing canonical URL
  • Open Graph and Twitter card tags with the hero image
  • JSON-LD BlogPosting schema with headline, description, image, datePublished, dateModified, author and publisher
  • JSON-LD BreadcrumbList
  • Exactly one h1 per page, no skipped heading levels
  • Descriptive alt text on every image

Site-wide: Organization and WebSite JSON-LD, an XML sitemap, an RSS feed, and robots.txt pointing at the sitemap.

Then verify rather than trusting it:

curl -s https://yoursite.com/some-post/ | grep -o 'application/ld+json' | wc -l

Paste a post URL into Google’s Rich Results Test. If the structured data doesn’t validate there, it doesn’t exist as far as Google is concerned.

Don’t Load Everything on the Index

The default implementation reads every post’s full content to render a list of excerpts. Fine at 10 posts. Noticeably slow at 300.

The index and category pages must read only frontmatter, never full post bodies. Excerpts come from the description field, not from truncating content.

Images

Images are where blog performance goes to die.

Use Astro’s Image component for all images. Serve WebP with fallbacks, set explicit width and height to prevent layout shift, lazy-load everything below the fold, and eager-load the hero.

Layout shift from images without dimensions is both a ranking factor and genuinely irritating.

Internal Linking

Worth building in, because it’s the highest-leverage SEO work most blogs never do.

Add a related posts component showing 3 posts from the same category, excluding the current one, falling back to recent posts if there aren’t enough. Add previous/next navigation within the category.

Then check your own work:

Write a script that reads all markdown files, extracts internal links, and reports: posts with fewer than 2 internal links, posts with no inbound links from other posts, and any links to slugs that don’t exist.

Orphan posts — pages nothing links to — get crawled less and rank worse. This script finds them in seconds.

Adding a CMS Later

If non-technical writers arrive:

Add Sanity as the content source. Keep the same frontmatter shape so existing markdown still works. Set up a webhook that triggers a rebuild on publish. Add preview mode for drafts.

Keeping the schema identical means you can move without rewriting the site.

The Checklist

  • Statically generated, drafts excluded from production
  • Meta title and description on every page
  • Canonical URLs, self-referencing
  • Open Graph image renders correctly (test a real share)
  • BlogPosting and BreadcrumbList JSON-LD, validated in Rich Results Test
  • Organization and WebSite schema site-wide
  • XML sitemap generated and in robots.txt
  • RSS feed working
  • One h1 per page, hierarchy intact
  • Alt text on all images
  • Index pages read frontmatter only
  • Images optimised with explicit dimensions
  • No orphan posts
  • PageSpeed above 90 on mobile

The Thing Worth Remembering

Everything on that checklist is invisible. The blog looks finished without a single item done — which is exactly why AI skips them and why most AI-built blogs get no traffic.

A beautiful blog with no structured data, no sitemap, and no internal linking is a blog nobody finds. Ask for the invisible parts explicitly, then verify them with tools rather than by looking.

Related reading:

Frequently Asked Questions

What's the best CMS for an AI-built blog? +

Markdown files in the repo if you're the only writer — simplest, fastest, version controlled. Sanity or Payload if non-technical people need to publish. Avoid building your own editor; it's more work than it looks and nobody enjoys using the result.

Should a blog be statically generated or server-rendered? +

Statically generated. Blog content changes rarely, static pages are fast, and speed is a ranking factor. Use incremental static regeneration so new posts appear without a full rebuild.

What SEO does AI leave out of blogs? +

Nearly all of it. Meta descriptions, canonical URLs, Open Graph tags, Article structured data, XML sitemaps, and RSS feeds are all routinely missing, because none of them affect whether the page renders.

How do I stop my blog getting slow with lots of posts? +

Paginate the index rather than rendering every post, generate pages statically at build time, and don't load full post content on listing pages. A blog that fetches every post's body to show excerpts gets slower with every article.

Tagged:

#vibe-coding #blog #cms #seo #tutorial

Enjoyed this article?

Get more AI tool picks, coding tutorials, and no-code automation guides every week. No spam, ever.

Found this useful? Share it:

More in No-Code & Low-Code AI