Architecture · SaaS|14 min read|

Enterprise SaaS Architecture: Decisions That Define the Business

Building a SaaS product is different from building custom enterprise software. Architecture decisions in a SaaS have direct business consequences: the multi-tenancy model determines your operational costs, security posture, and how easy it is to onboard an enterprise customer. This guide documents the architecture decisions that SaaS teams make (or should make) in the first weeks of development, before they become difficult to change.

Multi-tenancy: the central architectural decision of every SaaS

Multi-tenancy is how your system serves multiple customers (tenants) from the same infrastructure. The three main models have very different tradeoffs in cost, security, and operational complexity.

Silo Model: dedicated infrastructure per tenant

Each tenant has their own application instance and database. Isolation is total: a bug or breach in tenant A doesn't affect tenant B. Operational cost is high — each new tenant requires provisioning infrastructure. The right model for enterprise customers with compliance requirements (data in their own VPC, full database control).

Pool Model: shared database with tenant_id

All tenants share the same database. Isolation is managed at the application level with a tenant_id in every table. Operational cost is low — onboarding a new tenant is inserting a record. The risk: a tenancy leak bug (a query that forgets the tenant_id filter) can expose one tenant's data to another.

Bridge Model: schema per tenant in the same database instance

Each tenant has their own schema within the same PostgreSQL instance. Better isolation than Pool without the cost of separate instances. The complexity: managing schema migrations across all active tenants.

typescript
// Multi-tenancy middleware with tenant_id in Pool Model
import { AsyncLocalStorage } from 'node:async_hooks';

const tenantStorage = new AsyncLocalStorage<string>();

export const tenantMiddleware = async (req: Request, res: Response, next: NextFunction) => {
  const tenantId = req.auth?.tenantId;
  if (!tenantId) return res.status(401).json({ error: 'Tenant not identified' });
  tenantStorage.run(tenantId, () => next());
};

// Prisma extension: automatically add tenant_id to all queries
export const tenantPrismaExtension = Prisma.defineExtension({
  query: {
    $allModels: {
      async findMany({ args, query }) {
        const tenantId = tenantStorage.getStore();
        if (!tenantId) throw new Error('Tenant context not set');
        args.where = { ...args.where, tenant_id: tenantId };
        return query(args);
      },
      async create({ args, query }) {
        const tenantId = tenantStorage.getStore();
        if (!tenantId) throw new Error('Tenant context not set');
        args.data = { ...args.data, tenant_id: tenantId };
        return query(args);
      },
    },
  },
});
The Prisma extension (or equivalent in your ORM) that automatically adds tenant_id to all queries is the most important protection against tenancy leaks. Without it, a developer who forgets the manual filter can expose data between tenants — and that bug is very hard to catch in code review.

Usage-based billing: the SaaS financial engine

  • Flat rate: fixed monthly price. Simple to implement, predictable for the customer, but can penalize low-usage customers while subsidizing high-usage ones.
  • Per seat: price per active user. The most common in B2B SaaS. Natural incentive for customers to only keep the users they need.
  • Usage-based (consumption): price per unit of use (API calls, GB stored, transactions processed). Lower entry barrier, but unpredictable revenue. Growing trend in infrastructure and AI SaaS.
typescript
// Usage recording for consumption billing with Stripe Metered Billing
async function recordApiUsage(tenantId: string, count: number): Promise<void> {
  const subscription = await db.subscription.findUnique({
    where: { tenantId },
    select: { stripeSubscriptionItemId: true }
  });
  if (!subscription?.stripeSubscriptionItemId) return;

  await stripe.subscriptionItems.createUsageRecord(
    subscription.stripeSubscriptionItemId,
    {
      quantity: count,
      timestamp: Math.floor(Date.now() / 1000),
      action: 'increment',
    }
  );
}

Automated onboarding: the flow that determines retention

In B2B SaaS, time-to-value is the metric most correlated with retention. A customer who reaches first concrete value in under 24 hours is 3x more likely to convert from trial to paid than one who takes a week. Technical onboarding must be fully automated.

Feature flags and plans: SaaS access control

typescript
const PLAN_FEATURES = {
  starter: ['api_access', 'basic_reports', 'email_support'],
  professional: ['api_access', 'advanced_reports', 'webhooks', 'priority_support', 'sso'],
  enterprise: ['api_access', 'advanced_reports', 'webhooks', 'priority_support', 'sso',
               'custom_domain', 'audit_logs', 'dedicated_support', 'sla_guarantee'],
} as const;

async function hasFeature(tenantId: string, feature: string): Promise<boolean> {
  const tenant = await getTenantWithPlan(tenantId);
  const planFeatures = PLAN_FEATURES[tenant.plan as keyof typeof PLAN_FEATURES] ?? [];
  return (planFeatures as string[]).includes(feature);
}

if (!await hasFeature(tenantId, 'webhooks')) {
  return res.status(402).json({
    error: 'This feature requires the Professional plan or higher',
    upgradeUrl: '/settings/billing'
  });
}

SaaS observability: business metrics as technical metrics

  • Alert when the number of active tenants in the last 24h drops 20% vs. weekly average (signal of possible login or critical feature issue)
  • Track feature adoption by plan (what % of Professional tenants use SSO) to inform roadmap decisions
  • Monitor average onboarding completion time by signup cohort

Frequently Asked Questions

Which multi-tenancy model should I choose for a new B2B SaaS?
Pool Model (shared database with tenant_id) to start. It's the simplest to implement, has the lowest operational cost, and lets you validate the business quickly. If you land enterprise customers with data isolation requirements, you can offer the Silo Model as a premium option at higher price, keeping Pool Model for the mid-market segment.
How do I handle data security between tenants in the Pool Model?
Three defense layers: (1) ORM extension that automatically adds tenant_id to all queries (the most important), (2) PostgreSQL Row Level Security as a second verification layer independent of the application, and (3) automated tenancy isolation tests that verify endpoints don't return other tenants' data. Without all three layers, Pool Model has real tenancy leak risk.
Stripe or a custom billing system for a SaaS?
Stripe for practically all SaaS up to several million ARR. Stripe's cost (~2.9% + $0.30/transaction) is negligible compared to building and maintaining a system with equivalent capabilities: dunning management, multiple payment methods, metered billing, tax compliance. Building custom billing only makes sense at extreme scale or with very specific regulatory requirements.
How do I design architecture to support SSO/SAML that enterprise customers require?
Enterprise customers typically require SAML 2.0 or OIDC for SSO with their corporate IdP (Okta, Azure AD, Google Workspace). The correct implementation: use a specialized library (passport-saml for Node.js, python-saml for Python) or a dedicated service (Auth0, WorkOS) that abstracts protocol complexity. WorkOS is specifically designed to add enterprise SSO to an existing SaaS in days, not weeks.
How do I manage database migrations in a SaaS with many tenants in Bridge Model?
Bridge Model requires running the migration on all schemas for all tenants. The correct pattern: versioned migrations (Flyway, Liquibase) run as part of the deploy, with a script that iterates all active tenants and applies the migration to each schema. Migrations must be idempotent and backward compatible to support rollback. For tenants with very large schemas, run migrations in parallel with controlled concurrency.

Are you building a SaaS product and want to make the right architecture decisions from the start? Our team can guide you through the design.

Talk to our team

Related articles

IQS

Engineering Team — IQS

Software, cloud, and DevOps engineers with enterprise project experience.