Most agencies manage client sites the same way: separate repos, separate deployments, separate everything. When you have 5 sites, it’s manageable. At 15+, it’s a nightmare.
Every bug fix gets applied 15 times. Every design improvement means 15 pull requests. Shared components drift apart until each site is its own snowflake.
There’s a better way. We manage 15+ production sites from a single Astro monorepo, and in this post, we’ll show you exactly how the architecture works.
The Architecture
The monorepo uses pnpm workspaces with Turborepo for orchestration. Here’s the structure:
monorepo/
├── apps/
│ ├── client-site-a/ # Independent Astro app
│ ├── client-site-b/ # Independent Astro app
│ └── client-site-c/ # Independent Astro app
├── packages/
│ ├── layouts/ # Shared page layouts & components
│ ├── shortcodes/ # Shared UI components
│ ├── config-loader/ # Unified config system
│ └── types/ # Shared Zod schemas
├── pnpm-workspace.yaml
└── turbo.json
Each app in apps/ is a complete Astro site. Each package in packages/ is a shared dependency. Apps import from packages. Packages never import from apps.
How Shared Packages Work
The layouts package contains everything that’s common across sites: page layouts, navigation, footer, blog templates, SEO components. Apps import them like any npm package:
---
import Base from "@wumty/layouts/layouts/Base.astro";
import BlogHero from "@wumty/layouts/loaders/BlogHero.astro";
---
<Base title={title}>
<BlogHero />
</Base>
When you fix a bug in Base.astro, every site gets the fix on its next build. No copy-pasting. No drift.
Per-Site Customization via Config
Each site has its own src/config/ directory with JSON files that control branding, SEO, navigation, and theming:
{
"siteName": "Client Site A",
"base_url": "https://clienta.com",
"logo": "/images/client-a-logo.svg",
"logo_text": "ClientA"
}
The shared layouts read these config files at build time. Same layout code, different output per site. This is how 15 sites share one set of layouts but look completely different.
Per-Site Theming
Each site gets its own Tailwind CSS config that extends a shared base:
// apps/client-site-a/tailwind.config.mjs
import baseConfig from "@wumty/config-loader/tailwind-base";
export default {
...baseConfig,
theme: {
extend: {
colors: {
primary: "#2563eb", // Client A's brand blue
secondary: "#1e40af",
}
}
}
};
Colors, fonts, spacing, and component variants are all configurable per site without touching shared code.
Content Collections With Zod Validation
Every site uses Astro Content Collections with Zod schemas defined in the shared types package:
export const servicesCollection = defineCollection({
schema: z.object({
title: z.string(),
description: z.string(),
hero: heroSectionSchema,
cta: ctaSectionSchema.optional(),
}),
});
If a client’s content file has a missing field or wrong type, the build fails with a clear error message. Content bugs get caught at build time, not in production.
Independent Deployments
Each site deploys independently. Turborepo’s dependency graph ensures that when you change a shared package, only the affected sites rebuild:
# Build only sites affected by changes
turbo run build --filter=...[HEAD^1]
Site A’s deployment never blocks Site B. You can ship updates to one client without touching the others.
The Workflow for New Client Sites
Adding a new client site takes about 30 minutes:
- Copy an existing app as a scaffold
- Update
src/config/files with client branding - Replace content in
src/content/directories - Adjust theme colors in Tailwind config
- Deploy
The first site took weeks to build. The second took days. By site 5, it was under an hour. That’s the compounding return of shared architecture.
Common Pitfalls
Don’t share too much. If only 2 out of 15 sites need a component, it doesn’t belong in shared packages. Keep shared code genuinely universal.
Pin your dependencies. Use exact versions in pnpm-workspace.yaml to prevent version drift across sites.
Test shared changes across sites. A CI pipeline that builds all affected sites before merging shared package changes saves you from breaking 15 sites at once.
Getting Started
If you’re managing 4+ client sites, a monorepo will save you significant time. The Wumty Agency Kit ships with this exact architecture pre-configured: pnpm workspaces, Turborepo, shared packages, per-site theming, and migration tooling. The included migration script automates the tedious parts - scaffolding from an existing site, merging config files, converting content formats, and fixing common schema validation issues - so you can focus on client-specific customization rather than boilerplate setup.
For smaller setups (1-3 sites), the Single Site gives you the same template quality without the monorepo complexity.
Compare the options on our pricing page to find the right fit for your agency.
Ready to consolidate your client sites into one codebase? The Agency Kit gives you the monorepo architecture described in this post. Start smaller with the free Starter Kit or compare all options on the pricing page.