Architecture & Pattern·8 min read

One engine, many domains

The multi-tenant pattern behind a sports network, a 50-state platform, and a family of atlases: one backend and one frontend serving many public sites.

By Andrew J. Pyle

The first time I built a good site, it was a project. The second time I wanted a nearly identical site for a different subject, I almost rebuilt the whole thing from scratch before I stopped and asked the only question that matters: what is actually different between these two?

The answer was almost nothing. This is the multi-tenant pattern I use across several networks: one engine, many domains, where standing up the next site is a configuration change, not a new codebase.

01A NETWORK IS NOT N WEBSITES

The wrong unit of work

The first time I built a good site, it was a project. The second time I wanted a nearly identical site for a different subject, I almost rebuilt the whole thing. Then I asked the only question that matters at that point: what is actually different between these two?

The answer was almost nothing. The data was different. The colors were different. Everything underneath was the same. That gap, between what changes and what I was about to rewrite, is where the real work lives.

A network is not N websites. It is one machine that builds websites. Stop building sites. Build the thing that stands them up.

02DATA, THEME, COPY

What actually differs per tenant

Once you look honestly at two near-identical sites, the list of real differences is short. Everything else belongs in the shared core.

Per tenantShared engine
The data for this subjectThe models and the data layer
The theme and colorsThe components and page templates
The copy and the domainRouting, rendering, SEO, deploy

If something that should be shared is living inside one tenant, that is a bug, even if the site works. The discipline is keeping tenant-specific things out of the core.

03REFACTOR BECOMES PLATFORM

The extraction is the product

The platform is rarely designed up front. It is extracted. You build one site, then a second that is almost the same, and the refactor that pulls the shared parts out is the moment you stop having a site and start having a platform.

After that, standing up the next site is a configuration change, not a new codebase. New data, new theme, new domain, same engine. That is the asset.

04THE TRADE-OFFS

What you buy, and what it costs

What you buy is leverage. One improvement to the engine lifts every site at once. One bug fix fixes the whole network. The marginal cost of the next site drops toward the cost of its data.

What it costs is discipline. A shared engine means a mistake is shared too. Every change is a change to all tenants, so you test like it matters, and you keep the per-tenant surface as thin as the real differences.

05THE PART NOBODY TALKS ABOUT

Do not extract too early

The opposite mistake is just as expensive: building a platform for a single site. Abstraction you do not need yet is a tax you pay on every change with no network to spread it across.

Wait for the second, ideally the third, near-identical site. Let the real duplication tell you what to extract. The pattern earns its keep only once there is more than one tenant to carry it.

06NEXT STEPS

How to start

  1. Take two sites you would build the same way and write down what is actually different.
  2. If the list is only data, theme, and copy, you have a tenant model, not two projects.
  3. Extract the shared core only when the duplication is real, not anticipated.
  4. Make the next site a configuration change, and keep the per-tenant surface thin.

Have something you need built or fixed?

I build production Django / Next.js platforms and human-supervised AI-agent systems. Solo, senior, and fast. Tell me what you are building.

Start a project