One Codebase, Seventeen Blogs: How the Multi-Site Astro Setup Works
This blog network looks like seventeen websites but deploys from one codebase with zero per-site code. The thesis for builders: environment-driven content loading (one SITE_ID, one glob, one layout set) makes multi-tenancy nearly free — at the cost of build-time scaling linearly with site count.
The three moving parts
First, site resolution: src/lib/site.ts reads SITE_ID from the environment, loads sites/<id>/site.json, and exports the config plus the content path. No database, no CMS — the filesystem is the database, and site.json is the row. Second, content loading: the Astro content collection uses a glob loader pointed at the active site’s content/ folder, so getCollection("blog") transparently returns whichever site’s essays are active. Third, orchestration: scripts/build-all.mjs iterates every folder containing site.json, rebuilding Astro per site into dist/<id>/, plus a directory index build.
Why it works for agent fleets
The contract surface is tiny — site.json schema, Markdown frontmatter, AGENTS.md conventions — so parallel writers (human or model) need no coordination beyond filenames. Builds validate everything: broken frontmatter fails the build instead of shipping. And static output deploys anywhere; here it ships to Cloudflare Pages via the deploy script.
The counterpoint: limits of the design
Linear build scaling already costs ~20 seconds for 17 sites; at 100 sites it becomes minutes, and per-site builds duplicate identical assets. There’s no preview-per-site without env juggling, no shared taxonomies across sites, and filesystem-as-database means no concurrent-write safety — as this week’s disappearing-blog incident demonstrated. Real multi-tenancy eventually wants a CMS layer or at least a lockfile convention.
Takeaway
For fleets of small content sites, this pattern hits a sweet spot: boring technology, total ownership, agent-writable contracts. Outgrow it deliberately — when build minutes or write conflicts hurt — not preemptively.