Skip to content

008 · ARCHITECTURE

One instance per client: why we did not build a multi-tenant

Every client of Agora and m2 runs on its own release, its own database and its own tunnel. What that costs us, what it saves the client, and why the security questionnaire stops being a debate.

The default, and why we left it

The default architecture for a software product sold to many clients is the multi-tenant: one application, one database, a column that says which rows belong to whom. It is cheaper to run and easier to upgrade, and it is what almost every SaaS does. It also means that every client's data sits in the same table as every other client's, separated by a filter that has to be right on every query, forever.

For a régie, a social-housing landlord or a fund, that sentence is the whole problem. Their security officer will ask where the data is, who else is on the same server, what happens if another client's load or another client's incident reaches them. With a multi-tenant the honest answers are 'in the same table', 'everyone', and 'it depends'. We did not want to give those answers, so we built the other way.

What an instance is

Each client gets its own release of the application, the same code as everyone, built and deployed for them, its own PostgreSQL database, and its own tunnel to the network, so that the instance has no public surface beyond the one it serves. Nothing is shared at runtime: not a process, not a table, not a connection. A query cannot reach another client's rows because there are no other client's rows to reach.

The code is shared; the running system is not. That is the distinction that matters to a questionnaire: the answer to 'is our data isolated' is yes because of how it is built, not because a policy says so.

What it costs, and what it saves

It costs us a deployment per client instead of one, and a fleet to watch instead of a server. We pay that with automation: every instance is described in one manifest, built the same way, upgraded in the same window, and monitored on the same screen. The cost is real but it is ours, and it does not grow with the number of pages a client publishes.

It saves the client three things. An outage or a runaway load at another client is invisible to them. A security incident, should one ever happen, has a blast radius of one. And the end of the contract is a hand-back, not an extraction: their database is a database, exported as SQL with the media and the data dictionary, and the instance is erased with a written record. There is no 'your rows among ours' to untangle.

When multi-tenant is right anyway

Multi-tenant is the right answer for a product with thousands of small clients and no questionnaire: Wodloop, our gym-management product, is one, and it would be foolish to run a database per CrossFit box. The rule is not 'never multi-tenant'; it is 'the architecture follows the buyer'. A public operator buys isolation, hand-back and a clear answer to a security officer. That is worth a deployment.

It also shapes the product: because every client is an instance, a client can have its own module set, its own domain, its own single sign-on, its own release cadence when a rule changes for them alone. Those are features a multi-tenant sells as 'enterprise'; here they are what the architecture already is.