When a booking platform handles 10,000 different businesses’ customer data, where exactly does each business’s data live?
Two architectural patterns dominate:
Pattern 1: Shared database, row-level isolation.
One Postgres database. Every customer record has a
tenant_id column. Application code filters by
tenant_id on every query. Most SaaS works this way.
Pattern 2: Per-tenant database.
Each business gets its own isolated database. No
shared rows, no tenant_id filtering. The database
is the isolation boundary.
Both work. They have different security and operational characteristics.
Pattern 1: shared database
Pros:
- Simpler operationally (one database to manage)
- Easier to run cross-tenant analytics
- Lower per-tenant cost at scale
- Schema migrations apply once
Cons:
- Data isolation depends on application code being
bug-free (one missing
tenant_idfilter = data leak across businesses) - Shared performance characteristics (one tenant’s noisy query affects all)
- Backup/restore is all-or-nothing
- Compliance harder (some regulations require physical isolation)
This is how most SaaS booking software works.
Pattern 2: per-tenant database
Pros:
- Hard data isolation (no shared tables means data can’t leak)
- Independent backup/restore per tenant
- Independent performance per tenant
- Easier compliance story
- Tenant-specific features / configuration
Cons:
- More complex operationally (1 database per tenant)
- Cross-tenant analytics requires aggregation
- Schema migrations have to apply to each tenant
- Higher per-tenant cost at small scale
This pattern is becoming common at the edge — especially on Cloudflare D1, where database creation is a single API call and the cost per database is near zero.
Why isolation matters for booking software
Booking platforms hold:
- Customer names, emails, phones (PII)
- Service history (sometimes sensitive — medical, therapy, intimate services)
- Payment instruments (if processed)
- Booking patterns (who goes where when)
A bug or breach that exposes data across tenants is catastrophic — for the platform AND for every business using it.
Examples of what’s gone wrong:
- A SaaS bug exposed customer data across 30,000 businesses for 4 hours
- A PostgreSQL row-level-security misconfiguration leaked data to read-only API consumers across tenants
- A misconfigured Elasticsearch index leaked support ticket data across tenants
Every shared-database SaaS lives one bug away from this kind of breach.
Per-tenant database changes the threat model
With per-tenant databases:
- A bug in query construction can only leak data within a tenant (which is fine — that’s the customer’s own data)
- Cross-tenant leaks become impossible at the database layer
- The “missing WHERE clause” class of bugs is defanged
This is a meaningful security improvement.
Compliance considerations
Some regulations specifically prefer or require per-tenant isolation:
- HIPAA (US health data): physical separation preferred
- GDPR (EU): right-to-be-forgotten is easier with per-tenant
- Canada PIPEDA, India DPDP: per-tenant simplifies compliance arguments
- PCI-DSS (payment card data): isolation reduces scope
If your business handles regulated data, per-tenant isolation reduces compliance burden.
Operational reality
The hidden cost of per-tenant databases is operations:
- Schema migrations: have to roll across all tenants
- Monitoring: per-tenant metrics
- Backups: separate restore points per tenant
- Sandbox / test data: per-tenant fixtures
For platforms that aren’t designed for it from day one, retrofitting per-tenant is expensive. For platforms designed for it, the operations are tractable.
Cloudflare D1 makes this practical
Cloudflare D1 is uniquely well-suited:
- D1 creation is an API call (sub-second)
- No per-database cost; pricing is by query / storage
- D1 is replicated automatically
- Schema migrations can be scripted across tenants
- D1 + Workers means edge-local data + edge-local code
This is what allows Zedule to run per-tenant D1 at $100/year/tenant. On AWS, the same architecture would cost $30-100/month/tenant just in infrastructure.
What to ask vendors
When evaluating booking software:
-
“Is each business’s data in its own database?” Vendors will hedge (“we use row-level security”). Press for specifics.
-
“What happens if I want a backup of just my data?” Per-tenant DBs make this easy. Shared DBs make this require export/dump.
-
“What happens if another business has a data breach?” Per-tenant: nothing happens to you. Shared: you may be in scope.
-
“Do you have shared compute, shared cache, shared queues?” Even with per-tenant DBs, shared compute can leak.
How Zedule does it
Zedule’s architecture:
- Each business gets a Cloudflare D1 database (one per tenant)
- Tenant routing via Cloudflare KV (slug → D1 binding)
- Pool workers handle multiple tenants but per- request the worker connects to one tenant’s D1
- No shared customer tables; no shared booking tables
- Per-tenant backups via Cloudflare API
This is what gives the platform-wide promise: your customer data is yours, isolated, on your tenant’s own database.