ArticleWeb Development

5 Architecture Decisions That Will Define Your SaaS Web App

Demo Author
Placeholder

Most architecture decisions are easy to get wrong and expensive to undo. Not because the wrong choice is catastrophically bad — usually it's fine — but because by the time you realise you made the wrong call, you have users depending on the current design, data structured around the current assumptions, and an engineering team that's built up a mental model of how everything fits together.

These are the five decisions that matter most in the early stages of a SaaS project, and the reasoning that should drive each one.

1. Multi-Tenant vs Single-Tenant

This is the most consequential architecture decision in SaaS, and it needs to be made before you write a line of application code.

Single-tenant means each customer gets their own isolated environment — separate database, separate deployment, sometimes separate infrastructure. Salesforce used to run this model. It's operationally expensive (each new customer requires a new deployment) but offers complete isolation and is easier to comply with strict data residency requirements.

Multi-tenant means all customers share the same database and application, with data isolated at the row level (using a tenant_id or organisation_id column on every table). This is how most modern SaaS works — Notion, Linear, Vercel, and almost every B2B SaaS you use is multi-tenant.

The practical decision:

For almost every early-stage SaaS, the answer is multi-tenant. The operational overhead of single-tenant (provisioning new environments, managing multiple deployments, keeping them in sync) is genuinely hard to justify when you have fewer than 50 customers and a team of fewer than 5 engineers.

The things that should push you toward single-tenant:

  • Enterprise contracts that require dedicated infrastructure
  • Data that's regulated in a way that prohibits commingling (certain healthcare, finance, government data)
  • Performance requirements so extreme that shared infrastructure can't meet them

Multi-tenant isolation at the database level does require discipline — every query must filter by tenant, every API endpoint must verify that the requesting user belongs to the tenant they're querying. This is the kind of thing that benefits from being enforced at the framework level rather than being a convention developers are expected to remember.

2. Monolith vs Microservices

The microservices pattern is genuinely useful at scale. It allows large teams to deploy services independently, scale specific components without scaling everything, and isolate failures to a subset of functionality. Netflix, Amazon, and Uber use it for good reasons.

It is almost always wrong for a SaaS product with fewer than 50,000 users, a team of fewer than 10 engineers, and a product that hasn't found product-market fit yet.

The costs of microservices that are easy to underestimate:

  • Every cross-service call is a network call — latency, failure modes, and retry logic all need to be handled explicitly
  • Distributed tracing is required to debug production issues across service boundaries
  • Data that could be a foreign key relationship is now a network call or an event
  • Independent deployments require independent CI/CD pipelines, which require coordination
  • Local development with multiple services requires orchestration (docker-compose with 8 services, or something like that)

Build a monolith. Structure it well — clear module boundaries, no circular dependencies, well-defined interfaces between domains — and you'll be able to extract services later if you genuinely need to. The discipline that makes microservices manageable (clear interfaces, small services, well-bounded contexts) is exactly the same discipline that makes a well-structured monolith easy to evolve.

The rule of thumb we use: if you don't have a specific, demonstrated bottleneck that a monolith cannot address, it's not time for microservices.

3. Auth Strategy

Authentication is not a feature you should build from scratch in 2026. The security requirements are non-trivial, the attack surface is large, and the failure mode (a security breach) is catastrophic. Use an established library or service and configure it for your needs.

The real decision is which authentication methods to support:

Email and password is the default expectation. It requires secure password hashing (bcrypt, argon2), rate limiting on login attempts, a functioning password reset flow, and email verification. It's well-understood and universally supported by users.

OAuth (Google, GitHub, Microsoft) — users log in with an existing identity provider. Dramatically reduces friction for sign-up (no new password to create or remember). Appropriate for products whose users are likely to have a Google or GitHub account. B2B SaaS almost always should support Google OAuth.

Magic links — an email containing a one-time sign-in link, no password required. Reduces the attack surface (no passwords to steal) and friction (no password to forget). Works well for apps where users might log in infrequently. The downside is dependency on email deliverability.

SAML/SSO — enterprise customers often require integration with their own identity provider (Okta, Azure AD). This is a significant implementation effort and is typically gated behind an enterprise plan.

What we recommend for early-stage SaaS: email/password plus Google OAuth, with magic link as an option if your user research suggests password friction is a problem. Don't implement SAML until an enterprise customer asks for it and is willing to pay for it.

The other auth decision is session management: JWT vs server-side sessions. JWTs are stateless and scale horizontally without shared session storage, but revoking them requires extra infrastructure (a token blacklist or short expiry times). Server-side sessions are easy to revoke but require a shared session store (Redis) if you're running multiple server instances.

4. Database Schema Design for SaaS

The two patterns that affect almost every SaaS schema:

Tenant isolation: As discussed above, if you're multi-tenant, every resource table needs a tenant_id or organisation_id. This should be added at schema creation time — retrofitting it later means a migration on every table plus updating every query. Use database-level row security policies in PostgreSQL if you want the isolation enforced at the database layer rather than the application layer.

Soft deletes vs hard deletes: Most SaaS should use soft deletes (a deleted_at timestamp rather than actually removing rows). Users expect to be able to undo actions. Compliance requirements often mandate data retention. Hard deletes break foreign key relationships in ways that are hard to reason about. The downside is that every query needs to filter on deleted_at IS NULL — enforce this at the ORM or query builder level.

Schema flexibility vs normalisation: The temptation to use a JSONB column for "flexible" data is real, but it has costs — you lose the ability to query efficiently on that data, and you lose schema enforcement. Use JSONB when the data is genuinely schemaless (user-submitted metadata, webhook payloads) and normalise everything that has a predictable structure.

Migrations: Use a migration tool from day one. Every schema change should be a versioned, reviewed, reversible migration. Running direct ALTER TABLE statements in production is how you end up with a database that doesn't match your application's assumptions.

5. Real-Time vs Polling

The question is usually framed as "do we need WebSockets?" and the answer is almost always "not yet."

Polling — the client requests new data every N seconds — is simple, reliable, and surprisingly effective. A 15-second polling interval is invisible to users in most contexts (notifications, status updates, activity feeds). It works with standard HTTP infrastructure, doesn't require persistent connections, and is trivial to implement with any data fetching library.

Server-Sent Events (SSE) — the server pushes updates to the client over a persistent HTTP connection, but the connection is one-directional (server to client). Good for real-time feeds, live activity logs, or progress updates where the client doesn't need to send data back.

WebSockets — persistent, bidirectional connections between client and server. Required for collaborative editing, chat, live presence indicators, and anything where the user's input needs to be reflected in other users' screens in near-real-time. WebSockets add infrastructure complexity (connections need to be managed across server instances, which requires a message broker like Redis Pub/Sub or a managed service) and stateful connection handling.

Our default: Start with polling. It's less impressive to describe in a pitch deck but it works, it's reliable, and it deploys without additional infrastructure. Switch to SSE if you need server-push for specific features. Only adopt WebSockets when you have a specific feature that genuinely requires it.

Making These Decisions Well

Architecture decisions made under time pressure or without full information tend to be the ones that get regretted. The value of a discovery process before development starts is that these questions get asked — and answered — before they're encoded in a codebase.

For most SaaS projects, these architecture decisions interact directly with your tech stack choice — the framework you build on can either make these patterns easier or harder to enforce. They also have a direct impact on how much your web app costs to build: multi-tenancy, auth complexity, and real-time features each have a meaningful budget impact.

Before these decisions get made, it's worth working through what belongs in your MVP scope — many architecture decisions can be deferred or simplified when the scope is clearly defined.

If you're at the stage of thinking through architecture for a new SaaS project, our custom development service covers this as part of every engagement. Our Web App MVP package includes a scoping session specifically to work through these decisions before a line of code is written. If you want to talk through your specific situation first, get in touch.

For a broader introduction to custom web app development, see our complete guide.

Related Posts