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
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
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.


