SaaSOctober 12, 20267 min read

Choosing a SaaS architecture before product-market fit

In short

Until you have found your market, a SaaS architecture should be cheap to change: a modular monolith, a shared database with a tenant ID on every row, access checks on the server and in the database, configuration in the environment. Decide early only what is expensive to reverse — the tenancy model, the authentication approach, customer data export and a log of architecture decisions — and postpone the rest until real load and paying customers show up.

Contents
  1. 01The main criterion is cost of change, not scale
  2. 02Tenancy model: shared, dedicated or mixed resources
  3. 03A modular monolith instead of microservices
  4. 04What to build in from day one
  5. 05What to postpone on purpose — and the signal to revisit
  6. 06Recording decisions so they can be revisited
  7. 07When an outside view helps

The main criterion is cost of change, not scale

Before a product finds its market, you don’t know the essentials: which features will matter, who will pay and how much. An architecture built for a million users is, at that point, a bet on a future that may not happen. Martin Fowler’s note “Monolith First” frames it as a question: when you begin a new application, how sure are you that it will be useful to your users? Until you are sure, speed of feedback matters more than scalability.

The practical takeaway is to split decisions into two kinds. Some are easy to change in six months: the cache, the queue, the UI library. Others drag data and customers along with them: get them wrong and the fix means migrating every tenant or making users sign up again. Time before investment is best spent on the second kind.

Tenancy model

Cost of a mistake later
High: touches the data schema, access and every customer
What to do now
Define who a tenant is and carry its ID everywhere

Authentication

Cost of a mistake later
High: switching providers means migrating user accounts
What to do now
Use a proven provider or library; don’t build your own

Schema of core entities

Cost of a mistake later
Medium to high: migrations on live data
What to do now
Think through IDs and relationships for the two or three main entities

Splitting into services

Cost of a mistake later
Low, if module boundaries are clean
What to do now
Postpone; keep modules inside one application

Cloud provider

Cost of a mistake later
Medium
What to do now
Keep configuration in the environment; don’t tie yourself to unique services without a reason
Decisions that are expensive to change later

Tenancy model: shared, dedicated or mixed resources

A tenant is whoever’s data must be kept apart from everyone else’s. In B2B that is usually a customer company and its employees; in B2C it may be a person, a family or a group. Microsoft’s multitenancy guidance stresses that choosing a model is a commercial decision as much as a technical one, because it shapes cost per customer, compliance requirements and what you can sell.

Shared (pool)

How it works
One application and one database, a tenant ID on every row
Pros
Cheapest to run, one update for everyone
Cons
An access-check bug can expose other tenants’ data; a heavy tenant affects the rest

Dedicated (silo)

How it works
A separate database or whole stack per customer
Pros
Strong isolation, simpler regulatory story
Cons
Cost grows with every customer; updates must roll out to every copy

Mixed (bridge)

How it works
Some components shared, some dedicated
Pros
A large or regulated customer can be split out
Cons
The code must support both modes

The terms pool, silo and bridge come from the AWS Well-Architected SaaS Lens; Microsoft describes the same options as fully multitenant, vertically partitioned and horizontally partitioned deployments. For an early B2B product, a sensible default is shared resources with a tenant ID and access checks in two places: in application code and in the database. In PostgreSQL the second line of defence is Row Level Security: once enabled, row access is denied until a policy explicitly allows it. One detail from the documentation matters: the table owner normally bypasses these policies unless you enable FORCE ROW LEVEL SECURITY.

Whatever model you choose, test it: a user of one tenant must not reach another tenant’s data through the interface or the API. Microsoft specifically recommends testing your isolation model rather than trusting that it is “built into the architecture”.

A modular monolith instead of microservices

Fowler observes that almost all successful microservice stories started with a monolith that got too big and was broken up. The reason is simple: before you find your market, you don’t know where the real domain boundaries lie, and moving a boundary inside one application is far cheaper than moving it between separately deployed services with their own databases and contracts.

A modular monolith is one deployable application split into modules by business capability: billing, users and access, the core product flow, notifications. Modules talk through explicit interfaces, and each database table belongs to a specific module. When a real reason to extract a service appears — a separate team, a different load profile, isolation requirements — the boundary is already drawn.

Modular monolith now

  • One build, one deploy, one database
  • A cross-cutting change is one task
  • Debugging in a single process
  • A small team needs no separate platform

Microservices now

  • Network calls, contract versions, distributed failures
  • A cross-cutting change touches several services
  • Tracing and shared observability needed from day one
  • Boundaries fixed before the product is understood

What to build in from day one

None of this needs a large team. Each item is cheap at the start and expensive to retrofit into a product with live customers.

  • A tenant ID in every table holding customer data, plus tests that check isolation.
  • Authentication through a proven provider or library; roles live inside the tenant, permissions are checked on the server.
  • Configuration and secrets in environment variables rather than code, as The Twelve-Factor App methodology suggests.
  • Separate development, staging and production environments, kept as similar as possible.
  • Database schema changes as migrations in the repository.
  • Tenant data export in a clear format: customers will ask for it, and so will due diligence later.
  • An audit log of significant actions: who changed permissions, deleted data or switched plans, and when.
  • Backups and a tested restore.
  • Application logs as an event stream you can search and analyse.
  • Plans and limits as data, not as conditions scattered through the code.

What to postpone on purpose — and the signal to revisit

Postponing is not ignoring. A good habit is to record, for each postponed decision, the signal that should bring it back. That turns avoided complexity into a deliberate choice instead of a gap.

Extracting microservices

Signal to revisit
A separate team owns the module, or it has a fundamentally different load profile

A separate database per customer

Signal to revisit
A customer requires isolation by contract or regulation, or one tenant noticeably degrades the others

Multiple hosting regions

Signal to revisit
Real customers have data-residency or latency requirements

An in-house billing engine

Signal to revisit
Your pricing model no longer fits what the payment provider supports

Sharding and complex caching

Signal to revisit
Measured bottlenecks under real load, not a forecast

Kubernetes and an internal platform

Signal to revisit
The number of services and environments is more than the team can run in simpler ways

Recording decisions so they can be revisited

A year from now nobody will remember why this tenancy model or that authentication provider was chosen — and those are exactly the questions a new technical lead, a team taking over the product or an investor’s technical expert will ask. A simple tool is the Architecture Decision Record (ADR), a format proposed by Michael Nygard.

  • Title — a short phrase: “Shared database with a tenant ID”.
  • Context — the forces and constraints at play: number of customers, requirements, team, timeline.
  • Decision — what was decided, in active voice.
  • Status — proposed, accepted, deprecated or superseded.
  • Consequences — all of them, not only the positive ones: what got easier, what got harder, which signal would force a revisit.

Records live in the repository next to the code, are numbered sequentially, and numbers are never reused. When a decision is reversed, the old record stays, marked as superseded with a link to the new one. A dozen such records explain an architecture better than a long document that has drifted away from the code.

When an outside view helps

A one-off consultation is most useful at three points: before choosing the tenancy model and the schema of core entities; when the first large customer asks for isolation or special data-storage terms; and before raising investment, when you want to be sure the architecture and decision records will stand up to a technical expert’s questions. In all three cases it helps to arrive with a brief: what the product does, who the tenant is, which integrations and data are involved, what the constraints are.

Tell us about your task — we'll review your request and get back to you

Got a project?
We'll scope and estimate it — for free.

Tell us about the product or the problem. After reviewing the task we'll come back with an architecture, a timeline and a price for the first version.

  • Scope and risks estimated before we start
  • NDA — yours or ours
  • Work starts within a week

Please do not send passwords, access keys or source code through this form — we will agree a safe way to share access separately.

By clicking the button you agree to the processing of your personal data.