SaaS·April 28, 2026·12 min read

Building Scalable SaaS Apps: Architecture Decisions That Matter

The infrastructure and architectural choices made at the start determine how fast you can grow — and how expensive growth becomes.

AM
Arjun Mehta
Lead Backend Engineer
SaaSArchitectureScalabilityBackendDatabase

Most SaaS scalability problems aren't infrastructure problems — they're architecture problems that were baked in at the start. Here's how to make the right decisions when the stakes are low and the options are open.

The SaaS companies that hit painful scaling walls at 1,000 customers rarely blame the right thing. They say 'our database is too slow' or 'our servers can't handle the load' — but the real problem is almost always an architectural decision made at month two that seemed harmless and became catastrophic at month eighteen.

Multi-Tenancy: Choose Your Model Before You Write Line One

Multi-tenancy is the single most consequential architectural decision in a SaaS application, and it's the one most founders defer until it's expensive to change. There are three patterns, each with clear trade-offs.

Shared Database, Shared Schema

All tenants share the same tables. A tenant_id column on every row provides isolation. This is the cheapest to operate and the simplest to build. It's the right choice for most early-stage SaaS products. The risk: a slow query by one tenant can degrade performance for all, and achieving true data isolation for compliance (SOC 2, HIPAA) requires row-level security.

Shared Database, Separate Schemas

Each tenant gets their own schema in the same database. Better isolation than shared schema, easier to take per-tenant backups, and simpler to add tenant-specific customisations. Works well up to ~500 tenants before connection management becomes painful. Good middle ground for mid-market SaaS.

Separate Database Per Tenant

Maximum isolation — required for healthcare, finance, and government customers. Also maximum operational overhead. Reserve this for enterprise tiers or regulated industries. Consider a hybrid: shared schema for lower tiers, dedicated database as an enterprise upsell.

The Queue is Not Optional

Every SaaS application beyond a basic CRUD app needs a job queue. The moment you have tasks that take more than 500ms, tasks that need to be retried on failure, or tasks that need to happen outside the request-response cycle — you need a queue. Ship it before you need it.

typescript
// Don't do this — blocks the HTTP response for 30 seconds
app.post('/api/export', async (req, res) => {
  const csv = await generateHugeCSV(req.body); // 30s
  await sendEmail(req.user.email, csv); // 5s
  res.json({ success: true });
});

// Do this — returns immediately, processes in background
app.post('/api/export', async (req, res) => {
  const jobId = await exportQueue.add({
    userId: req.user.id,
    filters: req.body,
  });
  res.json({ jobId, status: 'queued' });
});

Caching Strategy: The Four Layers

Caching in a SaaS app isn't one thing — it's four distinct layers, each solving a different problem.

  1. CDN cache: Static assets and public pages. TTL in days. Invalidate on deploy.
  2. Application cache (Redis): Session data, rate limit counters, computed values that are expensive to regenerate. TTL in minutes to hours.
  3. Query cache: Results of expensive DB queries that don't change per-request. Invalidate on data mutation.
  4. HTTP cache headers: ETag and Last-Modified for API responses. Lets clients skip full response parsing on unchanged data.

Database Indexes: The Most Underrated Performance Lever

Before reaching for read replicas, horizontal sharding, or caching — make sure your database indexes are right. The majority of 'our database is slow' problems we diagnose are actually 'your query is doing a sequential scan of 10M rows because there's no index on that column.' EXPLAIN ANALYZE is your best friend. Add indexes on every foreign key, every column used in WHERE clauses on large tables, and every column used in ORDER BY on paginated queries.

I've never encountered a SaaS application at Series A scale that was properly indexed. Adding the right indexes is almost always cheaper than horizontal scaling.

Feature Flags Are Infrastructure, Not a Nice-to-Have

Feature flags let you deploy code to production without enabling it for users. This enables continuous deployment without feature branches, percentage-based rollouts to catch regressions before they hit everyone, per-customer feature enablement for enterprise deals, and instant kill switches when something goes wrong at 2am. LaunchDarkly is the enterprise standard. Growthbook is open-source and excellent. Build your own if you have very simple needs — but have something.

The Billing Layer: Build It Right the First Time

Billing is the one area where a bug directly costs money — either yours (failed charges) or your customers' (incorrect charges). Use Stripe. Don't build your own subscription management. Make sure you handle: webhook idempotency (Stripe sends webhooks multiple times), failed payment recovery with dunning, proration on plan changes, and usage-based billing if applicable. The Stripe documentation for SaaS subscriptions is genuinely excellent — read it before writing a line of billing code.

KEEP READING

Related Articles

← BACK TO BLOG