Skip to content
priya.dev
all projects
status: production

Multi-tenant SaaS with Billing

Tenant-isolated SaaS platform with usage-based Stripe billing

View code
Next.jsTypeScriptPostgreSQLPrismaStripeClerkRedisResendVercel

Overview

What this is

A multi-tenant SaaS platform where organizations can switch between workspaces, data is isolated per tenant at the database level, and billing enforces usage limits automatically across three subscription tiers.

Problem

Why it needed building

Multi-tenant systems fail in two classic ways: data leaking across tenant boundaries, and billing state drifting out of sync with what a customer actually has access to (especially around failed payments and plan changes).

Solution

How it works

Clerk handles organization switching and identity, while row-level data isolation in PostgreSQL guarantees one tenant can never read another's data — enforced at the database layer, not just in application code. Stripe subscription webhooks (created, updated, cancelled, past-due) are processed with idempotency keys, and a failed payment automatically triggers plan downgrade enforcement at the API layer.

Architecture

How it's put together

  • Row-level security in PostgreSQL for per-tenant data isolation, not just query-level filtering
  • Clerk organization switching for multi-workspace identity management
  • Three billing tiers with usage-based limits enforced at the API layer, not just checked in the UI
  • Idempotent Stripe webhook handlers covering the full subscription lifecycle

Challenges

The hard part

Keeping billing state consistent with actual access required treating 'payment failed' as a first-class state machine transition, not an afterthought — a downgrade has to be enforced immediately and automatically, not caught later by a support ticket.

Trade-offs

What I gave up on purpose

Enforcing usage limits at the API layer (rather than trusting the frontend) adds a check to every relevant request, but it's the only way to guarantee a downgraded tenant can't keep exceeding their plan through direct API calls.

Performance

What changed, measurably

Billing state inconsistencies reduced to zero through idempotent webhook handling and automated downgrade enforcement on payment failure.

Next

What I'd build next

Add self-serve plan comparison and proration preview before a tenant confirms an upgrade or downgrade.