When a product serves several business customers, one of the first architecture decisions is how to separate them. Should every client company share one application and database, with their data separated by a tenant identifier? Or should each client get its own deployment: its own app instance, its own database, sometimes its own server?
Both approaches run successful products. The right choice depends on your clients, your team and how you expect the product to grow. For NeonTask, the field-service platform I designed, built and run, each client company runs on its own deployment. This post explains the trade-offs and why that choice fit.
The two models
Multi-tenant (shared). One application and usually one database serve every client. Each row of data carries a tenant identifier, and every query filters by it. A new client is a new record, created in seconds.
Single-tenant (per-client deployment). Each client gets its own instance of the application and its own database. The code is the same for everyone; the data and runtime are separated. A new client means provisioning a new deployment, ideally automatically.
There are hybrids too, such as one application with a separate database per client, or a separate schema per client in a shared database.
Data isolation
This is often the deciding factor.
In a shared system, isolation depends on every query in the code filtering by tenant correctly. One missed filter, in one endpoint or one report, can expose one client's data to another. Good frameworks and patterns reduce the risk, such as row-level security in the database or a global filter applied automatically, but it never disappears completely.
With per-client deployments, a bug in a query can only expose data within the same client. Isolation is structural, not a matter of discipline. For clients who are sensitive about their data, who compete with each other, or whose contracts require separation, this is a strong argument.
Cost
Shared systems are cheaper per client at scale. Resources are pooled, and a client with little activity costs almost nothing.
Per-client deployments carry a base cost for each client: memory, a database, backups, monitoring. Containers make this much lighter than it used to be, because many small deployments can run on the same server, but the overhead is real. The model fits best when you have a moderate number of clients, each paying enough to justify it, rather than thousands of small accounts.
Updates and versions
In a shared system, everyone is on the same version. You deploy once, and every client gets the change. Simple, but also risky: a bad release affects everyone at once.
With per-client deployments, you can:
- Roll out a release to one client first, then the rest.
- Schedule updates around a client's busy periods.
- Hold back a client if a change needs coordination with them.
The cost is discipline. Without automation, deployments drift apart and you end up maintaining several versions. The answer is a CI/CD pipeline that builds once and deploys the same image to every client, with the version tracked per deployment. NeonTask uses Dockerized services with a CI/CD pipeline that builds and ships every change, which is what keeps per-client deployments manageable. See a CI/CD pipeline for a small team.
Customization
Clients ask for different things: their own branding, extra fields, different workflows, specific reports.
In a shared system, every customization must be built as configuration, because all clients run the same code. That is healthy discipline, but some requests become awkward.
Per-client deployments make configuration per client natural, since each has its own settings and database. The danger is the opposite: it becomes tempting to fork the code for one client. Avoid that. Keep one codebase, and express differences through configuration and feature flags.
Performance and noisy neighbours
In a shared system, one client running a heavy report or importing a large dataset can slow down everyone else. You mitigate it with limits, queues and careful query design.
With separate deployments, a heavy client mostly affects itself, and you can give a large client more resources without touching the others. See how far a single server can take your product.
Operations
Shared systems have fewer moving parts: one app, one database, one set of backups. Per-client deployments multiply them: many databases to back up, many instances to monitor, many migrations to run.
This is manageable only with automation:
- Scripted provisioning of a new client deployment.
- Database migrations run automatically on deploy for each client.
- Backups per client, with restores tested. See Postgres backups that actually restore.
- Monitoring that shows the health of every deployment in one place. See monitoring and alerts for a small product.
Data residency and client requirements
Some clients need their data stored in a particular country or region, or on infrastructure they approve. Larger organizations, including many in the GCC, may also ask for their own environment as a condition of purchase. Per-client deployments make these requests straightforward: you deploy that client where it needs to be. In a shared system, they can require a separate installation anyway.
Security beyond the data
Isolation is not only about the database. In a shared system, file uploads, caches, search indexes, background jobs and logs must all be tenant-aware as well. Photos uploaded by one client should never be reachable through another client's links, and an error log should not mix sensitive details from several companies. With per-client deployments, these concerns are separated by default, which removes a whole category of subtle mistakes.
Leaving
When a client leaves, a per-client deployment can be exported and handed over cleanly, then deleted. In a shared system, extracting and deleting one client's data across shared tables takes more care.
How to choose
Lean towards multi-tenant when:
- You expect many small customers, including self-service sign-ups.
- Clients are similar and customization is limited.
- Lowest cost per customer matters most.
Lean towards per-client deployments when:
- You have fewer, larger business clients.
- Data isolation is a selling point or a contractual requirement.
- Clients want control over update timing or hosting location.
- You have, or can build, solid deployment automation.
For NeonTask, which serves several facility-maintenance companies that each manage their own clients, sites and finances, per-client deployments were the natural fit. For a consumer-facing booking app like Pro Clean+, the question does not arise in the same way, because there is one business and many customers.
Designing so you can change later
Whichever model you start with, a few habits keep options open:
- Keep the code single-tenant-friendly and tenant-aware at the same time: a clear tenant context everywhere, even if there is only one.
- Avoid hardcoding client-specific behaviour.
- Automate deployments and migrations from the start.
- Keep configuration in the database or environment, not in code.
That way, moving from per-client to shared, or offering a dedicated deployment to a large client of a shared product, is a project rather than a rewrite.
Summary
Multi-tenant systems win on cost and simplicity at scale. Per-client deployments win on isolation, flexibility and client trust, at the price of automation work. Choose based on who your customers are, not on what is fashionable.
If you are designing a B2B product and want help with the architecture, read about me, see the NeonTask case study, and get in touch.