Arquitectura Multi-Tenant: Cómo Cadences Escala
Un deep dive técnico en cómo servimos miles de organizaciones con aislamiento total de datos, latencia de milisegundos y costes que escalan linealmente.
Construir un SaaS para un cliente es relativamente sencillo. Construir uno que sirva a miles de organizaciones simultáneamente, con datos completamente aislados, rendimiento consistente y costes predecibles... eso es un desafío de arquitectura de otro nivel. En este artículo explicamos cómo lo hemos resuelto.
🏗️ Audiencia
Este artículo es técnico. Está pensado para CTOs, arquitectos de software y desarrolladores senior que quieran entender las decisiones de diseño detrás de Cadences. Si te gustan los diagramas de arquitectura y las discusiones sobre trade-offs, este es tu artículo.
Database per Tenant vs Shared Database
El primer gran dilema de cualquier arquitectura multi-tenant es cómo manejar los datos. Hay dos enfoques clásicos:
✕ Shared Database
Todos los tenants en una sola base de datos con `tenant_id` en cada tabla.
- + Más simple de mantener
- + Migraciones unificadas
- − Riesgo de data leak
- − Noisy neighbor problem
- − Escalabilidad limitada
✓ Database per Tenant
Cada organización tiene su propia base de datos completamente aislada.
- + Aislamiento total de datos
- + Sin noisy neighbor
- + Backup/restore por tenant
- − Más infraestructura que gestionar
- − Migraciones coordinadas
Cadences eligió Database per Tenant. ¿La razón? Gracias a Cloudflare D1, el coste operativo de gestionar miles de bases de datos es prácticamente cero.
El Stack de Cadences
Edge Layer: Cloudflare Workers
275+ puntos de presencia globales. Código ejecuta en < 10ms desde el edge más cercano al usuario. Zero cold starts.
State Layer: Durable Objects
Estado mutable con consistencia fuerte. Cada organización tiene sus propios DOs para sesiones, rate limiting, WebSocket hubs y locks distribuidos.
Data Layer: D1 (SQLite en el Edge)
Una base de datos D1 por organización. SQL completo, transacciones ACID, réplicas de lectura globales. Backups automáticos.
Storage Layer: R2 + KV
R2 para archivos y media (compatible S3). KV para configuraciones, caché y feature flags. Ambos edge-native.
Cómo se Resuelve el Tenant
Cuando una petición HTTP llega a Cadences, lo primero que ocurre es identificar a qué organización pertenece. Esto se hace en menos de 1ms:
// 1. Extract org from JWT token
const token = request.headers.get('Authorization');
const { orgId } = await verifyJWT(token);
// 2. Resolve org's D1 database binding
const db = env[`DB_ORG_${orgId}`];
// 3. Route to org's Durable Object
const doId = env.ORG_STATE.idFromName(orgId);
const orgState = env.ORG_STATE.get(doId);
// 4. Execute query on org's isolated database
const contacts = await db
.prepare("SELECT * FROM contacts WHERE active = 1")
.all();
// No `WHERE org_id = ?` needed → the entire DB is this org's
Observa la última línea: no hay WHERE org_id = ?. No hace falta. Toda la base de datos pertenece a esa organización. Es imposible acceder accidentalmente a datos de otro tenant.
Garantías de Aislamiento
Data Isolation
Cada org tiene su propia D1 database. No hay posibilidad física de cross-tenant data access.
Compute Isolation
Workers ejecutan en V8 isolates. Cada request corre en su propio contexto aislado con limits de CPU/memoria.
Storage Isolation
Archivos en R2 bajo prefix por org. KV namespaces con org-scoped keys. Sin posibilidad de colisión.
Auth Isolation
JWT tokens firmados por org con HMAC-SHA256. Un token de org A no funciona contra org B, nunca.
Migraciones Coordinadas
El mayor reto operativo de database-per-tenant es ejecutar migraciones de esquema en miles de bases de datos. Nuestro enfoque:
Versionado de esquema
Cada D1 tiene una tabla _migrations que trackea qué versión de esquema tiene. Similar a Flyway/Liquibase, pero en SQLite.
Lazy migration
Las migraciones se aplican on-demand cuando un tenant hace su primera request tras un deploy. Esto distribuye la carga en lugar de ejecutar 5.000 migraciones a la vez.
Batch migration worker
Un worker programado (cron) recorre las orgs que llevan más de 24h sin migrar y aplica las migraciones pendientes en background.
Safe migrations only
Solo se permiten migraciones backward-compatible: ADD COLUMN sí, DROP COLUMN nunca en el mismo deploy. Breaking changes se hacen en 2 fases.
Modelo de Costes Edge-Native
Una de las preguntas más frecuentes es: "¿No es carísimo tener una database por tenant?" La respuesta corta: no, con Cloudflare D1 es más barato que la alternativa centralizada.
| Componente | Modelo de coste | Coste típico / org |
|---|---|---|
| D1 Database | $0.75/M reads, $1/M writes | ~$0.05/mes (org típica) |
| Workers | $0.30/M requests | ~$0.02/mes |
| Durable Objects | $0.15/M requests + storage | ~$0.01/mes |
| R2 Storage | $0.015/GB/mes | ~$0.03/mes (2GB media) |
| KV | $0.50/M reads | ~$0.01/mes |
| Total por organización | ~$0.12/mes | |
$0.12 por organización al mes para infraestructura completa. Compara eso con una instancia RDS en AWS ($50+/mes) o un cluster de PostgreSQL para multi-tenancy ($200+/mes). El edge-native approach no solo es más rápido — es órdenes de magnitud más barato.
Edge-Native vs Traditional Cloud
| Aspecto | AWS/GCP Traditional | Cadences (Edge-Native) |
|---|---|---|
| Cold start | 100ms - 10s (Lambda) | 0ms (V8 isolates) |
| Latencia global | 50-300ms (región central) | 5-20ms (edge local) |
| Escalado | Auto-scaling con lag | Instantáneo (por request) |
| Coste mínimo | $50-200/mes base | $5/mes (Workers Paid) |
| DevOps requerido | Alto (VPC, IAM, monitoring) | Mínimo (wrangler deploy) |
Lo que Hemos Aprendido
1. SQLite en el edge es sorprendentemente potente
D1 soporta CTEs, window functions, JSON functions, FTS5 full-text search. Para el 95% de las consultas SaaS, es más que suficiente.
2. Durable Objects resuelven problemas que parecían imposibles
Rate limiting por org, WebSocket hubs, distributed locks, session management — todo con consistencia fuerte y sin Redis.
3. La mayor complejidad está en las migraciones
El lazy migration pattern fue crítico. Sin él, cada deploy sería un cuello de botella. Con él, las migraciones son transparentes.
4. Monitorización distribuida requiere su propio tooling
Con miles de D1 databases no puedes usar pgAdmin. Construimos un dashboard interno (Heartbeat Studio) que muestra health, tamaño y queries lentas de cada org.
¿Quieres construir sobre esta arquitectura?
Si estás evaluando arquitecturas multi-tenant para tu SaaS, podemos ayudarte. Ofrecemos consultoría de arquitectura edge-native basada en nuestra experiencia real con Cadences.
Hablar con el EquipoConclusión
La arquitectura multi-tenant de Cadences demuestra que database-per-tenant no tiene por qué ser caro ni complejo. Con el stack correcto (D1, Workers, Durable Objects), obtienes aislamiento total, rendimiento global y costes que escalan linealmente con el número de clientes.
El edge-native approach no es solo una optimización de rendimiento — es un cambio fundamental en la economía del SaaS. Cuando tu infraestructura cuesta $0.12 por tenant al mes, las decisiones de negocio cambian radicalmente.
El edge no es el futuro. Es el presente. Y es sorprendentemente barato.