When I was on WordPress every client site lived somewhere different. Two on SiteGround, one on a cheap cPanel box the client bought themselves, a couple on WP Engine. Every login was a seperate password reset waiting to happen.

After moving most of them to Astro I put every client site in one repo. It sounds like a small thing but it changed how I run the whole agency, so here is the setup.

The folder layout

Nothing clever. One folder per client, each one is a normal Astro project:

clients/ bakery-surry-hills/ physio-newtown/ plumber-parramatta/ ... shared/ components/ checks/ AGENTS.md sites.json 

I use pnpm workspaces so shared/components (footer, contact form, cookie free analytics snippet, schema helpers) gets imported by every site. When I fix the footer once, every client gets it on the next deploy.

I did try one repo per client for a while. It was fine at 5 sites and a mess at 15. Dependabot PRs alone were a part time job.

sites.json is the source of truth

This file is the bit I'd keep even if I threw everything else away:

[ { "slug": "bakery-surry-hills", "domain": "www.example-bakery.com.au", "plan": "care", "contact": "owner@example-bakery.com.au", "lastDeploy": "2026-11-12" } ] 

Domain, which care plan they are on, who to email, when it last went out. My coding agent reads this before it touches anything, so when I say "update the opening hours for the bakery" it knows which folder and which domain without me spelling it out.

The rules file

AGENTS.md at the root is short. The important lines:

  • Only change files inside the client folder you were asked about, unless the task says shared/.
  • If you change anything in shared/, build every site, not just one.
  • Never deploy to production without running pnpm check for that site first.
  • After a deploy, update lastDeploy in sites.json.

The shared/ rule is the one that saved me. Early on the agent tweaked a shared component for one client and quietly broke the layout on three others. Now it has to build all of them and the build fails loud.

Deploying is one loop

Every site builds to its own dist, and every site is hosted in the same place. I use Novence for this so each client folder just does:

cd clients/bakery-surry-hills pnpm build && npx novence deploy ./dist 

For a shared change I have a tiny script that loops sites.json, builds each one, runs the checks and deploys. Twenty sites takes a few minutes. Before this, a footer change across all clients was an afternoon of logging into different dashboards.

Having all of them on one host also means one place for domains, forms and stats. When a client emails "is the site down?" I'm not trying to remember which provider they are on.

Monthly care plan, actually done

I sell a care plan per site. On WordPress that mostly meant plugin updates and praying. Now the monthly job is something I can hand to the agent:

  1. pnpm update across the workspace, build every site.
  2. Run the checks (broken links, missing meta, forms still post, redirects still 301).
  3. Deploy the ones that changed.
  4. Pull last month's visitor numbers per site and write a 5 line summary for each client.

I review the summaries, tweak the odd one and send them. Clients like getting the email more than they ever liked "we updated 14 plugins".

Things I'd do differently

  • Start sites.json on day one. Back-filling domains and contacts for 15 sites was boring.
  • Keep client specific stuff out of shared/. If only one client needs it, it lives in their folder, even if it's copy paste.
  • Pin Astro across the workspace. Mixed versions made the agent's job way harder than it needed to be.
  • Don't give the agent production deploy without the checks gate. It's fast enough that you'll be tempted. Dont.

If you're a small agency still juggling a pile of hosting logins, moving everything into one repo and one host is probably the highest value boring change you can make. It's not glamorous but it's the reason I can run 20 sites on my own.

How are other people handling multi client setups? Monorepo, or one repo per client?