ForgeStack
Full-stack SaaS starter with multi-tenancy, RBAC, and Stripe billing. Engineering reference implementation, not a product.
View RepositoryAt a glance
Provide a reference implementation for common SaaS patterns: multi-tenancy, authentication, authorization, and billing integration.
Engineering teams and developers who want to study production-grade SaaS architecture patterns.
- • Multi-tenancy with Row Level Security
- • Role-based access control (RBAC)
- • Stripe billing integration
Context
Building a SaaS product from scratch requires solving the same foundational problems repeatedly: authentication, authorization, multi-tenancy, and data isolation. These aren't differentiated features—they're table stakes. Yet getting them wrong can sink a product.
The Problem
Most SaaS starters cut corners on multi-tenancy. They either use tenant columns (leaky abstraction, error-prone) or separate databases (expensive, operationally complex). Neither approach provides the security guarantees enterprise customers demand.
Approach
ForgeStack implements true multi-tenancy using PostgreSQL's Row Level Security at the database layer. This means tenant isolation is enforced by the database itself—not application code that can have bugs. Combined with a strict RBAC system, it provides defense in depth.
Architecture
ForgeStack uses a monorepo structure with clear separation between the Next.js frontend and NestJS backend. Turborepo handles build orchestration, while pnpm workspaces manage dependencies. The backend exposes a typed API that the frontend consumes, with end-to-end type safety via shared types.
The architecture prioritizes developer experience without sacrificing production readiness. Hot reload works across the entire stack, and the testing infrastructure supports unit, integration, and e2e tests out of the box.
apps/
├── web/ # Next.js frontend
├── api/ # NestJS backend
packages/
├── db/ # Drizzle schema + migrations
├── shared/ # Shared types and utilities
├── config/ # Shared configurationSecurity & Multi-tenancy
Row Level Security (RLS) is the backbone of ForgeStack's multi-tenancy implementation. Every table with tenant data has RLS policies that filter rows based on the current session's tenant context. This happens at the database level, making it impossible for application bugs to leak data between tenants.
The RBAC system is built on top of this foundation. Permissions are scoped to tenants, and role assignments are verified on every request. The combination provides defense in depth—even if the application layer has a bug, the database layer prevents unauthorized access.
-- Every tenant-scoped table uses RLS
CREATE POLICY tenant_isolation ON projects
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- Application sets tenant context on each request
SET app.tenant_id = 'tenant-uuid-here';Tradeoffs
Every architecture involves tradeoffs. ForgeStack optimizes for:
• **Security over simplicity**: RLS adds complexity but provides strong guarantees • **Type safety over speed**: Strict TypeScript catches errors early but requires more upfront work • **Monorepo over microservices**: Simpler deployment and shared code, but tighter coupling
These tradeoffs make sense for most B2B SaaS products, but may not fit every use case.