Building a Multi-tenant CRM on Cloudflare Workers
How we architected a scalable CRM that handles thousands of organizations without database partitioning or complex infrastructure.

The Challenge
When building CRM software, multi-tenancy is non-negotiable. But traditional approaches—database partitioning, separate schemas per tenant, or even separate databases—introduce complexity that slows down development and increases operational overhead.
Our Approach
We built Verbira CRM on Cloudflare Workers with a tenant-first data model. Instead of partitioning, we use a composite key strategy: every record includes organization_id as the first column in indexes.
Data Model
interface Lead {
id: string;
organizationId: string; // First in every index
email: string;
stage: 'new' | 'qualified' | 'proposal' | 'won' | 'lost';
// ...
}
Build something similar?
Let's discuss your use case. We architect for performance, clarity, and growth from day one.
Query Isolation
Every database query automatically scopes to the current organization:
async function getLeads(orgId: string) {
return db
.select()
.from(leads)
.where(eq(leads.organizationId, orgId))
.orderBy(desc(leads.createdAt));
}
Results
- Zero cross-tenant data leakage (enforced at query level)
- Simple codebase: no tenant-aware middleware needed
- Fast queries: composite indexes make tenant lookups instant
- Easy to scale: D1 handles thousands of organizations without issues
Lessons Learned
- Index order matters:
organization_idmust be first in composite indexes - Middleware simplicity: One line
WHERE organization_id = ?instead of complex routing - Testing: Easy to test by swapping
organization_idvalues
Multi-tenancy doesn't have to be complex. With the right data model and edge-first architecture, you can build secure, scalable CRM systems that grow with your customers.