← Back to all posts
12 min readCentrali Team

How to Build a SaaS Backend: Complete Checklist for 2025

A comprehensive guide to building a production-ready SaaS backend. Covers multi-tenancy, authentication, data modeling, search, file storage, and serverless functions.

GuidesArchitectureTutorial

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):

sql
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:

typescript
// ❌ 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

  1. User signs up → Create account + default workspace
  2. User logs in → Issue JWT/session token
  3. Token includes workspace context
  4. Every API request validates token + workspace access

Authorization Patterns

Role-based access control (RBAC):

typescript
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:

typescript
// 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:

sql
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:

sql
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

SolutionProsCons
PostgreSQL full-textNo extra serviceLimited features
ElasticsearchPowerful, matureComplex, resource-heavy
MeilisearchFast, easy to useNewer, fewer features
AlgoliaManaged, fastExpensive 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 client

Implementation 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

typescript
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

TechnologyBest for
WebSocketsBidirectional, low latency
Server-Sent EventsOne-way updates, simpler
PollingFallback, high latency

Implementation

typescript
// 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 order

Always scope by workspace in the URL. This makes tenant isolation explicit and prevents accidental cross-tenant access.

Response Format

json
{ "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

typescript
// 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:

ComponentBuild TimeMaintenance
Multi-tenancy2-4 weeksOngoing
Auth & permissions2-3 weeksOngoing
Data layer3-4 weeksOngoing
Search2-3 weeksModerate
File storage1-2 weeksLow
Serverless2-4 weeksOngoing
Real-time2-3 weeksModerate
Total14-23 weeksHigh

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:

  1. Build from scratch — Full control, high effort
  2. Use Firebase/Supabase — Good for simple apps, limited multi-tenancy
  3. 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:

  1. Multi-tenancy — Row-level isolation is simplest
  2. Auth — JWT tokens with workspace context
  3. Data — Flexible schemas with JSONB
  4. Search — Async indexing, typo tolerance
  5. Files — Direct upload to cloud storage
  6. Functions — Event-driven business logic
  7. Real-time — WebSocket subscriptions
  8. API — Workspace-scoped REST endpoints
  9. Billing — Usage metering per tenant

Build what makes you unique. Use platforms for the rest.

Building something with Centrali and want to share feedback about this feature?

Email feedback@centrali.io