Building Scalable Multi-Tenant SaaS Applications with Node.js and PostgreSQL

Building a multi-tenant SaaS application is one of the most challenging yet rewarding architectural problems in software development. Having built Sals CRM — a multi-tenant SaaS platform — I've learned firsthand what works and what doesn't when serving multiple organizations from a single codebase.
What is Multi-Tenancy?
Multi-tenancy means a single instance of your application serves multiple customers (tenants). Each tenant's data is isolated, but they share the same application infrastructure. Think of it like an apartment building — everyone shares the building structure, but each apartment is private.
Three Approaches to Data Isolation
The most critical decision in multi-tenant architecture is how you isolate tenant data:
- Separate databases — Each tenant gets their own database. Maximum isolation but expensive to manage at scale.
- Shared database, separate schemas — All tenants share one database but have individual PostgreSQL schemas. Great balance of isolation and cost.
- Shared database, shared schema — All tenants share tables with a
tenant_idcolumn. Most cost-effective but requires careful query discipline.
For most SaaS applications, I recommend the shared database with separate schemas approach. PostgreSQL handles this exceptionally well.
Implementing Schema-Based Isolation in PostgreSQL
When a new tenant signs up, create their schema dynamically:
// On tenant creation
await db.raw(`CREATE SCHEMA IF NOT EXISTS tenant_${tenantId}`);
await db.migrate.latest({
schemaName: `tenant_${tenantId}`
});
Then, at the start of every request, set the search path based on the authenticated tenant:
// Middleware
app.use(async (req, res, next) => {
const tenantId = req.user.tenantId;
await db.raw(`SET search_path TO tenant_${tenantId}, public`);
next();
});
Role-Based Access Control (RBAC)
A robust RBAC system is essential. Design your roles table to be flexible:
- Super Admin — Platform-level access across all tenants
- Tenant Admin — Full access within their own tenant
- Manager — Can manage team members and view reports
- User — Standard access with limited permissions
Store permissions as granular actions (e.g., contacts:read, contacts:write, reports:export) and map them to roles. This gives you the flexibility to create custom roles per tenant.
Scaling Considerations
As your tenant count grows, monitor these areas:
- Connection pooling — Use PgBouncer to manage database connections efficiently
- Background jobs — Offload heavy operations (reports, emails) to a queue system like Bull or BullMQ
- Caching — Implement Redis caching with tenant-prefixed keys
- Monitoring — Track per-tenant resource usage to identify heavy users
Conclusion
Multi-tenant architecture demands careful upfront planning, but the payoff is enormous — you serve thousands of customers from a single, maintainable codebase. PostgreSQL's schema system combined with Node.js gives you a powerful, cost-effective foundation for building SaaS products that scale.