Building a bilingual blog with Astro
Creating content in more than one language doesn’t have to be complicated. In this post, I’ll show how I set up a bilingual (English/Spanish) blog using Astro’s Content Collections, simple folder structure, and a couple of dynamic routes.
Why Astro for a bilingual blog?
- Lightweight by default: static HTML where possible, islands when needed.
- First‑class Markdown/MDX support and type‑safe frontmatter via Content Collections.
- Simple file‑based routing that makes language prefixes straightforward.
Folder structure
I keep language variants side‑by‑side under src/content/blog and route them through language‑scoped pages:
src/
content/
blog/
en/
first-post.md
second-post.md
third-post.md
es/
primer-post.md
segundo-post.md
tercer-post.md
pages/
en/
blog/
[...slug].astro
index.astro
es/
blog/
[...slug].astro
index.astro
This keeps URLs clean (/en/blog/... and /es/blog/...) and ensures each language has its own listing and detail pages.
Content Collections schema
Astro’s Content Collections give me typed frontmatter and easy querying. My blog collection defines a minimal schema with title, description, pubDate, optional updatedDate, and an optional heroImage.
Frontmatter for each post follows the same shape in every language, so lists and feeds work consistently.
Writing posts (what I actually fill in)
Each post begins with frontmatter that matches the schema:
---
title: "My title"
description: "One‑sentence summary"
pubDate: "Aug 30 2025"
heroImage: "/blog-placeholder-1.jpg"
---
Then comes standard Markdown. I like to include:
- A short intro with the reader’s goal.
- A concrete example or code snippet.
- A call‑to‑action or links for next steps.
Routing and rendering
Language‑scoped routes (e.g., src/pages/en/blog/[...slug].astro) read the collection and render the matching entry based on the file path. Separate listing pages (/en/blog and /es/blog) query the same collection but filter by language folder.
Because frontmatter is typed, I get build‑time errors if I forget a required field or format a date incorrectly—super helpful for maintenance.
Extras: MDX and components
When a post needs interactive or styled callouts, I can switch to MDX or drop in Astro components. This keeps the default simple while letting me scale up post‑by‑post.
Deployment note
This site deploys to Cloudflare Workers. Astro’s adapter builds a static+edge bundle, so performance stays snappy across regions with minimal config.
Wrap‑up
That’s the whole setup: two language folders, a shared schema, and language‑scoped routes. It’s easy to maintain, SEO‑friendly, and fast. If you’re starting a new blog, I highly recommend this approach, especially if you plan to write in more than one language.