Building a SaaS backend is one of the most common—and most complex—engineering challenges. You need authentication, multi-tenancy, data storage, search, file handling, and serverless logic. This guide walks through every component you need and how to implement them.
The SaaS Backend Checklist
Before diving into implementation, here's what a complete SaaS backend needs:
- Multi-tenant architecture — Isolated data per customer/organization
- Authentication & authorization — User login, roles, permissions
- Data modeling — Flexible schemas for different customer needs
- Full-text search — Find records across all data
- File storage — Handle uploads, images, documents
- Serverless functions — Business logic without managing servers
- Real-time updates — Push changes to connected clients
- API design — RESTful or GraphQL endpoints
- Billing integration — Usage tracking, subscription management
Let's break down each component.
1. Multi-Tenant Architecture
Multi-tenancy is the foundation of any SaaS product. You need to isolate customer data while sharing infrastructure.
Three Approaches
Database-per-tenant:
customer_a → database_a
customer_b → database_b
customer_c → database_c- Pros: Complete isolation, easy backups per customer
- Cons: Expensive, complex migrations, connection pooling issues
Schema-per-tenant:
database → schema_customer_a
→ schema_customer_b
→ schema_customer_c- Pros: Good isolation, simpler than separate databases
- Cons: Still complex migrations, Postgres-specific
Row-level tenancy (recommended for most SaaS):
SELECT * FROM orders WHERE workspace_id = 'customer_a' AND status = 'pending';- Pros: Simplest to implement, easy migrations, efficient
- Cons: Requires discipline to always filter by tenant
Implementation Pattern
Every database query must filter by the tenant identifier:
// ❌ WRONG - No tenant filtering
const orders = await db.query('SELECT * FROM orders WHERE status = $1', ['pending']);
// ✅ CORRECT - Always filter by workspace
const orders = await db.query(
'SELECT * FROM orders WHERE workspace_id = $1 AND status = $2',
[workspaceId, 'pending']
);Tip: Use middleware to automatically inject the tenant context from the authenticated user's session.
2. Authentication & Authorization
SaaS apps need both authentication (who are you?) and authorization (what can you do?).
Authentication Flow
- User signs up → Create account + default workspace
- User logs in → Issue JWT/session token
- Token includes workspace context
- Every API request validates token + workspace access
Authorization Patterns
Role-based access control (RBAC):
const roles = {
admin: ['create', 'read', 'update', 'delete', 'manage_users'],
editor: ['create', 'read', 'update'],
viewer: ['read']
};
function authorize(user, action, resource) {
const permissions = roles[user.role];
return permissions.includes(action);
}Resource-based permissions:
// Check if user can access specific resource
const canAccess = await checkPermission({
userId: user.id,
workspaceId: workspace.id,
resource: 'orders',
action: 'read'
});3. Data Modeling
SaaS products need flexible data models that can evolve without breaking existing customers.
Schema Design Principles
Use JSON/JSONB for flexibility:
CREATE TABLE records (
id UUID PRIMARY KEY,
workspace_id UUID NOT NULL,
structure_id UUID NOT NULL,
data JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);Index what you query:
CREATE INDEX idx_records_workspace ON records(workspace_id);
CREATE INDEX idx_records_structure ON records(structure_id);
CREATE INDEX idx_records_data_email ON records((data->>'email'));Version your schemas: Track which version of a schema each record was created with, so you can migrate gracefully.
4. Full-Text Search
Users expect instant search across all their data.
Implementation Options
| Solution | Pros | Cons |
|---|---|---|
| PostgreSQL full-text | No extra service | Limited features |
| Elasticsearch | Powerful, mature | Complex, resource-heavy |
| Meilisearch | Fast, easy to use | Newer, fewer features |
| Algolia | Managed, fast | Expensive at scale |
Search Architecture
User searches → API → Search service → Return results
↑
Record created → Index to search service (async)Key considerations:
- Index on write, not on read
- Handle partial matches and typos
- Filter search results by tenant
- Return relevant metadata, not just IDs
5. File Storage
Every SaaS needs file handling—profile pictures, documents, exports.
Storage Architecture
User uploads → API → Cloud storage (S3/Azure/GCS)
↓
Save metadata to database
↓
Return CDN URL to clientImplementation Checklist
- Signed upload URLs (direct-to-storage)
- File size limits
- MIME type validation
- Virus scanning (for sensitive industries)
- CDN for fast delivery
- Tenant-scoped file access
6. Serverless Functions
Business logic that runs on events, schedules, or HTTP requests.
Common Use Cases
- On record create: Send welcome email, notify Slack
- On schedule: Generate daily reports, clean up old data
- On HTTP: Webhooks from external services
Function Pattern
export async function onOrderCreated(event, api) {
const { record, workspaceId } = event;
// Send confirmation email
await api.sendEmail({
to: record.data.customerEmail,
template: 'order-confirmation',
data: { orderId: record.id }
});
// Update inventory
for (const item of record.data.items) {
await api.updateRecord('inventory', item.productId, {
quantity: { $decrement: item.quantity }
});
}
}7. Real-Time Updates
Modern SaaS apps need to push changes to connected clients.
Options
| Technology | Best for |
|---|---|
| WebSockets | Bidirectional, low latency |
| Server-Sent Events | One-way updates, simpler |
| Polling | Fallback, high latency |
Implementation
// Client subscribes to changes
const subscription = centrali.subscribe('orders', {
filter: { status: 'pending' },
onUpdate: (record) => {
console.log('Order updated:', record.id);
}
});
// Later: cleanup
subscription.unsubscribe();8. API Design
Your API is how developers interact with your platform.
REST Patterns
GET /workspaces/:ws/orders # List orders
POST /workspaces/:ws/orders # Create order
GET /workspaces/:ws/orders/:id # Get order
PATCH /workspaces/:ws/orders/:id # Update order
DELETE /workspaces/:ws/orders/:id # Delete orderAlways scope by workspace in the URL. This makes tenant isolation explicit and prevents accidental cross-tenant access.
Response Format
{
"data": { "id": "123", "status": "pending" },
"meta": { "requestId": "abc-123", "timestamp": "2025-01-15T10:30:00Z" }
}9. Billing Integration
Track usage and integrate with payment providers.
Usage Metering
Track these metrics per workspace:
- API calls
- Storage used (bytes)
- Compute time (ms)
- Records stored
- Bandwidth consumed
Integration Pattern
// On each API request
await trackUsage({
workspaceId,
metric: 'api_calls',
value: 1
});
// Monthly billing job
const usage = await getMonthlyUsage(workspaceId);
await stripe.invoiceItems.create({
customer: workspace.stripeCustomerId,
amount: calculateBill(usage),
description: 'API usage for December 2025'
});Build vs. Buy Decision
Building a SaaS backend from scratch takes 3-6 months. Here's what you're signing up for:
| Component | Build Time | Maintenance |
|---|---|---|
| Multi-tenancy | 2-4 weeks | Ongoing |
| Auth & permissions | 2-3 weeks | Ongoing |
| Data layer | 3-4 weeks | Ongoing |
| Search | 2-3 weeks | Moderate |
| File storage | 1-2 weeks | Low |
| Serverless | 2-4 weeks | Ongoing |
| Real-time | 2-3 weeks | Moderate |
| Total | 14-23 weeks | High |
When to Build
- You need complete control over architecture
- Unique requirements not served by existing platforms
- Large team with backend expertise
- Long-term investment horizon
When to Use a Platform
- Speed to market matters
- Small team without dedicated backend engineers
- Standard SaaS requirements (90% of cases)
- Want to focus on product, not infrastructure
Getting Started
If you're building a SaaS backend, you have three paths:
- Build from scratch — Full control, high effort
- Use Firebase/Supabase — Good for simple apps, limited multi-tenancy
- Use Centrali — Built for SaaS with multi-tenancy, search, and compute included
Centrali handles multi-tenant workspaces, full-text search, serverless functions, and file storage out of the box. Learn more about SaaS backends with Centrali →
Summary
A production SaaS backend needs:
- Multi-tenancy — Row-level isolation is simplest
- Auth — JWT tokens with workspace context
- Data — Flexible schemas with JSONB
- Search — Async indexing, typo tolerance
- Files — Direct upload to cloud storage
- Functions — Event-driven business logic
- Real-time — WebSocket subscriptions
- API — Workspace-scoped REST endpoints
- Billing — Usage metering per tenant
Build what makes you unique. Use platforms for the rest.