Astro SEO Blog · Part 2

Building an Astro Blog with Claude Code

Instead of following a tutorial, I gave Claude one prompt and watched it install Astro, wire up Tailwind, MDX, RSS, and a sitemap, push to GitHub, and deploy to Vercel — all in one session.

· 7 min read
Contents
  1. The Prompt
  2. What Claude Installed
  3. What Claude Built
  4. The SEO Decisions Baked Into BaseLayout
  5. The Content Schema
  6. Where It Hit Problems
  7. Push to GitHub and Deploy
  8. The Result
  9. What This Actually Demonstrates
  10. Why the SEO Foundation Matters More Than the Framework
  11. Write Your First Post

In part 1 I explained why I moved from Lovable.dev to Astro for SEO. Lovable builds React apps that serve empty HTML to Googlebot — Astro builds static HTML that Google can read instantly, no JavaScript required.

This post is part 2: actually building the blog. But instead of walking you through every command manually, I handed it to Claude.

The Prompt

One prompt. That’s it.

Build me an SEO-ready Astro blog from scratch with Tailwind, MDX, RSS feed, sitemap, and fonts

From that, Claude installed everything, built the full project structure, and had a working blog ready to deploy. Here’s exactly what happened — including the decisions it made that I didn’t ask for, and where it hit problems.

What Claude Installed

Claude ran the following commands in sequence:

npm create astro@latest astro-demo

When prompted:

  • Template: Empty
  • TypeScript: Yes, strict
  • Install dependencies: Yes
  • Initialize git repo: Yes

Then added the integrations:

npx astro add tailwind
npx astro add mdx

Then fonts and RSS:

npm install @fontsource-variable/inter @fontsource/jetbrains-mono
npm install @astrojs/rss

One thing it caught that I didn’t ask about: it skipped @astrojs/sitemap entirely. That integration crashes on Astro 4.16+ with a Cannot read properties of undefined (reading 'reduce') error. Claude knew this and built a manual sitemap endpoint at src/pages/sitemap.xml.ts instead. That’s the kind of thing you only know if you’ve hit the bug — or in this case, if your agent has enough context to anticipate it.

What Claude Built

The full project structure:

src/
├── components/
│   ├── Header.astro
│   ├── PostList.astro
│   └── SeriesNav.astro
├── content/
│   └── posts/        # .md/.mdx files go here
├── layouts/
│   └── BaseLayout.astro
├── pages/
│   ├── index.astro
│   ├── about.astro
│   ├── archive.astro
│   ├── posts/[slug].astro
│   ├── tags/[tag].astro
│   ├── categories/[category].astro
│   ├── series/[series].astro
│   ├── rss.xml.ts
│   └── sitemap.xml.ts
└── styles/
    └── globals.css

The scope here is worth noting. I asked for a blog. Claude built a full content taxonomy — tags, categories, series navigation, archive page, RSS feed, sitemap. Every route it created serves a purpose for either discoverability or SEO.

The SEO Decisions Baked Into BaseLayout

This is the part most tutorials skip. The layout file is where most of your SEO either works or doesn’t.

Claude built BaseLayout.astro with the following automatically wired up for every page:

Canonical URL — generated from the site URL and current path. Every page declares its own canonical, which prevents duplicate content issues if Vercel’s preview URLs ever get indexed.

Open Graph tagsog:title, og:description, og:image, og:url, og:type. These control how the page appears when shared on Twitter, LinkedIn, or Slack. Claude wired them to the same frontmatter fields as the page meta, so there’s no separate OG configuration needed per post.

Twitter Cardsummary_large_image by default, so post shares show a full image preview rather than a small thumbnail.

JSON-LD structured data — three schemas per post page: Article, WebSite, and BreadcrumbList. These are what Google uses to understand the page type, authorship, and navigation hierarchy. On a CSR site this has to load via JavaScript and might not be seen by crawlers. On Astro it’s in the HTML before any JavaScript runs.

All of this is automatic. Drop a new post file in src/content/posts/, push, and every one of those meta tags is generated correctly with no manual input.

The Content Schema

Claude defined the content schema in src/content/config.ts:

title: string
description: string
publishDate: string
updatedDate?: string
tags: string[]
category: 'guides' | 'notes' | 'builds'
draft: boolean
image?: string
imageAlt?: string
series?: string
part?: number

The series and part fields were something I asked for specifically — I knew I’d want to group related posts. Claude built SeriesNav.astro to handle the series UI automatically: previous/next links within a series, plus a link back to the series index page. Posts without series in their frontmatter render as standalone, no extra configuration needed.

Where It Hit Problems

It wasn’t perfect. Two things needed manual fixes.

The Vercel deploy config. The first deploy failed because Vercel defaulted to the wrong output directory. Claude had to add a vercel.json file to the root:

{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "framework": "astro"
}

After that it deployed cleanly.

The GitHub push from the server. Claude Code runs on my homeserver, not my local machine. To push to GitHub from the server, the git remote needs a personal access token embedded in the URL — standard HTTPS auth doesn’t work in a headless environment. Claude flagged this and set the remote correctly:

git remote set-url origin https://TOKEN@github.com/username/repo

Not a Claude Code limitation — just a server environment reality. Worth knowing if you’re running agents on a remote machine.

Push to GitHub and Deploy

Once the remote was configured:

git add .
git commit -m "Initial blog build"
git push origin master

Then on Vercel: Add New Project → import the repo → Deploy. Vercel detects Astro automatically. No build settings needed beyond the vercel.json fix above.

Within two minutes the blog was live at a Vercel URL.

The Result

A fully working, SEO-ready Astro blog — deployed on Vercel, with tags, categories, series navigation, RSS, sitemap, JSON-LD schema, Open Graph, and canonical URLs — built from a single prompt in one session. The whole thing took just over 7 minutes of active Claude time.

Live demo: astro-demo-theta-tawny.vercel.app

What This Actually Demonstrates

The point isn’t that Claude wrote the code. It’s that agentic workflows collapse the gap between a decision and a working system.

The traditional path for this project: read the Astro docs, pick a template, configure Tailwind, wire up MDX, figure out why @astrojs/sitemap crashes, build the content schema, write the base layout, set up JSON-LD manually, troubleshoot the Vercel config, push. Half a day minimum, probably longer.

The agentic path: one prompt, review the output, fix two issues, ship.

The output is the same. The time investment is not.

That’s what this blog documents — not AI as a novelty, but AI as operational infrastructure. The blog itself was built the same way the systems it writes about are built: give the agent a clear goal, stay in the loop on decisions that matter, and let it handle the implementation.

Why the SEO Foundation Matters More Than the Framework

A lot of people building blogs with AI tools focus on the wrong thing. They want the blog to look good, deploy fast, and be easy to write in. Those matter. But the SEO foundation — the stuff that determines whether Google can read and understand your content — is decided before you write a single post.

Here’s what this build gets right by default:

Every page is crawlable on the first request. No JavaScript rendering required. Googlebot hits the URL, gets complete HTML, indexes it. That’s it.

Structured data is present and correct on every post. The JSON-LD schema Claude wired into BaseLayout.astro tells Google this is an Article, who authored it, when it was published, and where it sits in the site hierarchy. This is what enables rich results in SERPs — date stamps, breadcrumbs, author attribution. On a manually-built blog these are easy to get wrong or forget entirely. Here they’re generated automatically from frontmatter.

The sitemap updates on every deploy. The custom sitemap.xml.ts endpoint queries the content collection and generates a fresh sitemap at build time. Every new post is automatically included with its correct URL and publish date. You never manually update a sitemap or worry about a new post being missed.

RSS keeps returning readers engaged. The RSS feed at /rss.xml is a low-effort retention mechanism. Readers who subscribe get notified of new posts without you needing to send an email or post on social. For a technical blog, a meaningful chunk of the audience prefers RSS — it’s worth having from day one.

None of this required separate configuration. It was all handled in the initial build.

Write Your First Post

Drop a .md file in src/content/posts/:

---
title: "My First Post"
description: "A short description for Google."
publishDate: "2026-04-27"
tags: ["astro", "seo"]
category: "guides"
draft: false
---

Your content here.

Push to GitHub. Vercel redeploys automatically. Done.

Ted

Web Developer · SEO Operator · Security

I build web applications, run SEO campaigns, and dig into offensive security on the side. Most of what ends up here started as something I was already doing — agentic workflows, local LLMs, automation systems. This blog is the documentation layer.