If you have ever read the architecture diagrams for a modern SaaS product, you know the shape. There is one application. There is one database, partitioned by a tenant ID. There are many customers, all sharing the same compute and the same storage, separated only by a WHERE tenant_id = $1 clause in every query.
That is the standard. It is the standard for good reasons — it is operationally cheap, it scales horizontally, it lets a small team support a lot of customers, and the engineering effort to build it is well understood. Most of the SaaS companies you have heard of are built this way.
KeyDog is not built this way. Every KeyDog customer gets their own dedicated instance. Their own application container. Their own Postgres database. Their own backup chain. Their own subdomain. The instances do not share state with each other and they cannot accidentally leak data between each other, because there is no shared data path to leak through.
This was a deliberate choice, and it has costs as well as benefits. I want to walk through both honestly, because customers occasionally ask about it during evaluations and I think the trade-off is interesting.
What "one instance per customer" actually means
When you sign up for KeyDog, our provisioning system spins up a new application instance for your organisation. The pipeline is automated end-to-end and takes about ninety seconds in normal operation.
What that creates:
- A fresh container running the KeyDog application binary.
- A fresh Postgres 16 database, isolated to your instance, with its own connection pool.
- A subdomain, typically
yourorg.keydog.io, with its own TLS certificate issued through Let's Encrypt. - A fresh secrets bundle, including the session encryption key, the audit log signing key, and the database credentials. None of these are shared with any other customer instance.
- A backup chain that writes encrypted snapshots to object storage on a 4-hour cadence, with retention defined by your plan.
When your subscription ends, the inverse runs. The container is stopped and deleted, the database is dropped, the secrets are zeroized, the subdomain is released. A final encrypted snapshot is retained for 90 days in case you want to come back; after that, it is gone.
What this costs us
I want to be honest about the costs because they are real.
Compute is not free. A multi-tenant SaaS company can amortise compute very efficiently — a single application server can serve hundreds of small customers. We cannot do that. Every customer needs at least one running container, even if they only have three admin users and check out two keys a week. Our per-customer compute footprint is meaningfully larger than a comparable multi-tenant product.
Database operations are more complicated. Schema migrations have to be run against every customer database separately. A migration that takes one minute against one database takes thirty minutes when you have thirty customers. We have built tooling for this — rolling migrations with automatic rollback if any individual database fails — but it required engineering investment that a single-tenant company would not need.
Observability is harder. Aggregating metrics, logs, and traces across many independent instances is a more complex problem than aggregating them across one. We are using Grafana, Loki, and Tempo with per-instance labels to handle this. It works, but it took longer to build out than a single-tenant equivalent.
Per-customer overhead is higher. Things like password reset flows, billing reconciliation, support investigations — all of these require navigating to a specific customer's instance. We have built admin tooling that makes this efficient, but the cognitive load is non-trivial. A multi-tenant product has one global admin console; we have many small ones.
If we were trying to maximise gross margin, we would not have made this choice. We accepted lower gross margin because we believe the benefits to customers — and to our risk posture — outweigh the cost.
What this gets you
The benefits are concrete and they accrue to specific stakeholders inside your organisation.
For your security team
A breach of one customer's data cannot, by construction, leak another customer's data. The most common cause of cross-tenant data leakage in SaaS — a buggy WHERE tenant_id clause, an incorrectly cached result, a row-level security misconfiguration — does not exist in our architecture, because there is no shared data path. The only way to access your data is through your instance, with your credentials, against your database.
When your security team asks "what does the blast radius look like if KeyDog gets compromised at the application layer," the honest answer is "a compromised application instance can read its own database." That is the worst case for a single customer. For other customers, the answer is "the compromise does not reach them."
For your compliance team
Single-tenant architecture makes a number of compliance conversations much shorter. Data residency, for example: we can place your instance in a specific region (US-East, US-West, EU-West) on request, and the data physically does not leave that region. We cannot make that promise for a multi-tenant database, because the database does not respect customer-level placement.
Retention policies are also simpler. When your audit retention says "seven years," we configure your instance's backup retention to seven years. We do not have to reason about whether your data is mixed into a backup chain shared with customers who have different retention requirements.
For your facilities team
The day-to-day experience is identical to a multi-tenant SaaS, so most users will never notice the architecture. Where they do notice it is in performance. Because your application is not competing with other customers for database connections, query planner attention, or compute, performance is predictable. A noisy-neighbour problem — where another customer's heavy workload slows down yours — does not exist for you, because there are no neighbours.
The other place users notice it is during customisations. Custom PDF agreement templates, custom report queries, and integration-specific configuration are all isolated to your instance. We can deploy a hotfix to your instance for an urgent bug without coordinating it against a global release window. We can stage a feature flag for your instance to test a new capability before we expose it more broadly. The flexibility is meaningful.
What we cannot do
There are things a multi-tenant product can do that we cannot, and I want to be straightforward about them.
Cross-customer benchmarking. A multi-tenant SaaS can compute aggregate metrics across all its customers and show you "how does my key turnover rate compare to similar institutions." We cannot do this, because we do not have a single dataset to query against. We have considered building an opt-in benchmarking service that would aggregate anonymised metrics from consenting customers, but it is not built.
Some kinds of cross-tenant collaboration. If two of our customers wanted to share a key inventory — say, two campuses of the same university system that want to manage their access jointly — we cannot do that natively. They each have their own instance. We are exploring a "federation" model for Enterprise customers with multiple instances, but it is not generally available.
Real-time global rollouts. When we ship a new release, it rolls out instance by instance over a few hours. A multi-tenant product can flip a feature flag globally in milliseconds. The trade-off is that an instance-by-instance rollout is much safer — we have caught release-blocking bugs at the first 5% of instances and halted the rollout before any other customer was affected. We think this is the better trade, but it is a trade.
The bigger reason
The deepest reason we chose this architecture is that we believe a key management system is the wrong place to take shortcuts on isolation. The data we hold for a customer — who has access to what, when they got it, when they returned it, what their building floor plans look like — is operationally sensitive and would be useful to an attacker. We did not want to be in the position of explaining to a compromised customer why a bug in our row-level security caused their data to leak into someone else's instance.
The simplest way to never have that conversation is to make it architecturally impossible. That is what we did.
If you have questions about the architecture, or your security team would like to walk through the threat model with us in detail, we are happy to set up a call. We have done this with several institutional procurement teams and it is one of our favourite conversations to have.
See KeyDog for yourself
Replace the key spreadsheet. Spin up a live demo or talk to our team about your campus.