Multi-Tenant SaaS Applications
HeliosDB Lite runs the data of a multi-tenant SaaS application in shared tables: each tenant gets its own database role, a row-level security policy compares a tenant column with current_user, and the same policy filters PostgreSQL wire sessions and REST requests, because a REST request runs as the role named in its token, so every tenant sees only its own records.
Superusers bypass row-level security; give each tenant its own non-superuser role and start the server with SCRAM authentication so clients cannot claim another role. Read the documentation.
Executive Summary
- Zero operational complexity - no database management layer required
Problem Being Solved
The Multi-Tenancy Dilemma
SaaS platforms face a critical architectural trade-off:
Option A: Shared Database
- Pro: Operational simplicity (single database)
- Con: Catastrophic: Any tenant query can slow all tenants
- Con: Catastrophic: Bugs/attacks affect all tenants
- Con: Critical: Row-level security complex and fragile
- Con: Data breach = all customer data compromised
- Con: Noisy neighbor problem endemic
Option B: Database Per Tenant
- Pro: True isolation (separate database per tenant)
- Pro: Security: No cross-tenant contamination
- Con: Catastrophic: Each tenant needs backup, monitoring, patching
- Con: Scaling nightmare - managing hundreds of database instances
- Con: Complex connection pooling across database fleet
- Con: Retention policies, upgrades become operational burden
Enterprise Pain Points
Operational Burden:
- Managing separate connection pools for each tenant
- Setting up RLS (row-level security) policies in each database
- Backup/restore procedures for each tenant separately
- Scaling requires provisioning new instances (hours not minutes)
Security & Isolation Challenges:
- Shared database RLS bugs expose all customer data
- Connection pool misconfigurations leak tenant data between customers
- Noisy neighbor: one tenant's bad queries slow all others
- Audit trails mixed across all tenants
HeliosDB Lite Solution Architecture
Multi-Tenancy Isolation Model
Three-Layer Isolation Strategy:
┌─────────────────────────────────────────────────────────┐
│ Layer 1: Process Boundary Isolation │
│ ├─ Each tenant runs in separate database context │
│ ├─ No shared memory with other tenants │
│ └─ Operating system enforces process boundaries │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Layer 2: Cryptographic Branch Isolation │
│ ├─ Each tenant database = unique branch │
│ ├─ Branch identified by cryptographic hash (256-bit) │
│ ├─ Queries validated against branch token │
│ └─ Cross-branch access: Cryptographically impossible │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Layer 3: MVCC Snapshot Isolation │
│ ├─ Each query sees consistent snapshot │
│ ├─ Snapshot from specific branch only │
│ ├─ Isolation level: SERIALIZABLE per branch │
│ └─ Other branches' commits invisible │
└─────────────────────────────────────────────────────────┘
Deployment Architecture
Kubernetes StatefulSet - One Tenant Per Container:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: heliosdb-saas-app
spec:
serviceName: heliosdb-saas
replicas: 50 # Scale to 50K+ tenants across cluster
template:
metadata:
labels:
app: heliosdb-saas
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- heliosdb-saas
topologyKey: kubernetes.io/hostname
containers:
- name: saas-app
image: saas-app:latest
env:
- name: HELIOSDB_TENANT_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: HELIOSDB_DATA_DIR
value: /data/$(HELIOSDB_TENANT_ID)
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumeMounts:
- name: data
mountPath: /data
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
Implementation Examples
Example 4: Docker Compose - Multi-Tenant Development
# Dockerfile for multi-tenant SaaS app
FROM rust:latest as builder
WORKDIR /app
COPY Cargo.* ./
COPY src ./src
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y curl ca-certificates
COPY --from=builder /app/target/release/saas-app /usr/local/bin/
# Create data directory with proper permissions
RUN mkdir -p /data && chmod 700 /data
RUN useradd -m -u 1000 app
USER app:app
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/health || exit 1
ENTRYPOINT ["saas-app"]
# docker-compose.yml - Multi-tenant development environment
version: '3.8'
services:
# Load balancer - routes requests to appropriate tenant container
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- saas-app-1
- saas-app-2
# Tenant 1 - Customer A
saas-app-1:
build: .
environment:
TENANT_ID: customer-a
HELIOSDB_DATA_DIR: /data/customer-a
RUST_LOG: info
volumes:
- tenant-a-data:/data/customer-a
expose:
- 8080
# Tenant 2 - Customer B
saas-app-2:
build: .
environment:
TENANT_ID: customer-b
HELIOSDB_DATA_DIR: /data/customer-b
RUST_LOG: info
volumes:
- tenant-b-data:/data/customer-b
expose:
- 8080
volumes:
tenant-a-data:
tenant-b-data:
# nginx.conf - Route by subdomain to tenant
upstream tenant_a {
server saas-app-1:8080;
}
upstream tenant_b {
server saas-app-2:8080;
}
server {
listen 80;
# Route customer-a.localhost to container 1
server_name customer-a.*;
location / {
proxy_pass http://tenant_a;
proxy_set_header Host $host;
}
}
server {
listen 80;
# Route customer-b.localhost to container 2
server_name customer-b.*;
location / {
proxy_pass http://tenant_b;
proxy_set_header Host $host;
}
}
Example 5: Kubernetes Multi-Tenant Scaling
# helm/values.yaml - Multi-tenant scaling configuration
replicaCount: 50
image:
repository: saas-app
tag: "1.0.0"
# Resource limits per tenant container
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
# Tenant scheduling
tenantScheduling:
mode: "pod-per-tenant" # or "multi-tenant-per-pod" (30:1)
tenants_per_pod: 1
# Persistent storage per tenant
persistence:
enabled: true
storageClass: "fast-ssd"
size: 10Gi # Per tenant
# Auto-scaling based on tenant count
autoscaling:
enabled: true
minReplicas: 10
maxReplicas: 100
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# Add new container when reaching 30 tenants
tenantScalingPolicy:
replicas_per_tenant: "1/30" # 1 replica per 30 tenants
# Backup strategy - all tenants in one pod
backup:
enabled: true
schedule: "0 2 * * *" # Daily at 2 AM
retention: 30 # days
destination: "s3://backups/saas-tenants"
# Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: saas-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: heliosdb-saas-app
minReplicas: 5
maxReplicas: 200
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 30
Adoption Strategy
Phase 1: Proof of Concept
Objective: Validate HeliosDB Lite for multi-tenancy use case
Activities:
- Set up 3-tenant test environment
- Customer A (historical data)
- Customer B (new data)
- Internal tenant (for testing)
- Migrate one small customer's data
- Validate isolation
- Benchmark latency
- Test backup/restore
- Run performance tests
- Schema migration procedures
- Failure recovery scenarios
Phase 2: Pilot Rollout
Objective: Run parallel systems (old and new) for reliability validation
Activities:
- Deploy HeliosDB Lite alongside PostgreSQL
- Parallel writes to both systems
- Compare query results (consistency check)
- Monitor both systems simultaneously
- Onboard 10-20 pilot customers
- Mix of small, medium, large customers
- Different data patterns and query types
- Gather real production metrics
- Establish operational procedures
- Tenant provisioning automation
- Backup/restore procedures
- Incident response playbooks
- Monitoring & alerting rules
- Performance testing at scale
- Load testing (simulate peak customer loads)
Phase 3: Full Production Rollout
Objective: Migrate all customers to HeliosDB Lite, retire PostgreSQL
Activities:
- Monitor churn impact (should be zero)
- Gather production performance data
- Build confidence with each batch
- Decommission old infrastructure
- Remove PostgreSQL databases (one per week)
- Consolidate infrastructure costs
- Redirect savings to product development
- Optimize for production
- Fine-tune container resource limits
- Optimize Kubernetes scheduling
- Auto-scaling based on real workload patterns
- Measure business impact
- Cost reduction achieved vs. projected
- Revenue impact from new isolation features (compliance sales)
- Team productivity improvement (less ops overhead)
Conclusion
For SaaS platforms: HeliosDB Lite transforms multi-tenancy from an operational burden into a scalable, reliable, cost-effective foundation for growth.
Performance depends on workload and hardware. Published figures are measured on representative fixtures; see the benchmarks page and reproduce them on your own workload.