La risposta in 60 secondi
Tre modelli di isolamento credibili nel 2026:
- Database condiviso, schema condiviso, colonna tenant_id + Postgres RLS. Impostazione predefinita. Il meno costoso da gestire. Supporta 10.000+ tenant su un singolo cluster Aurora o Neon. La migrazione a schema-per-tenant in seguito è dolorosa ma possibile.
- Schema-per-tenant (schemi Postgres separati nello stesso database). L'upgrade enterprise. Utile per le conversazioni sull'«isolamento logico» con gli auditor senza raddoppiare il costo dell'infrastruttura. Supporta 200–2.000 tenant per cluster.
- Database-per-tenant. Carichi di lavoro regolamentati, deployment single-tenant, clienti che pagano 100.000+ USD/anno. Costoso da gestire, più facile da eliminare in modo pulito, più facile da giustificare negli audit regolamentati.
Scegli (1) per qualsiasi nuovo SaaS B2B. Aggiungi (2) al livello business quando firmi il primo contratto con un cliente che chiede «i miei dati sono isolati dagli altri tenant?». Aggiungi (3) solo per settori regolamentati o contratti VIP superiori a 100.000 USD ARR.
Tre modelli di isolamento — tradeoff
| Modello | Costo/tenant | Complessità operativa | Tenant/cluster | Argomento per gli audit |
|---|---|---|---|---|
| Schema condiviso + RLS | $0,05–0,50/mese | Bassa | 10.000+ | Isolamento logico tramite RLS |
| Schema-per-tenant | $2–8/mese | Media | 200–2.000 | Isolamento a livello di schema |
| Database-per-tenant | $25–150/mese | Alta | 1 per DB | Forte isolamento fisico |
Schema condiviso con RLS — l'impostazione predefinita corretta
Il pattern schema-condiviso-con-RLS è diventato la scelta predefinita degli ingegneri senior per i nuovi SaaS B2B nel 2026. Funziona così:
- Ogni tabella di dominio ha una colonna
tenant_id uuid references tenants(id)non nulla, indicizzata come parte di ogni query comune. - Postgres Row-Level Security è abilitato su ogni tabella di dominio.
- Ogni tabella ha una politica RLS:
USING (tenant_id = current_setting('app.tenant_id')::uuid). - Ogni request handler esegue
SET LOCAL app.tenant_id = '...'all'inizio della sua transazione, derivato dal token di autenticazione verificato. - Il ruolo del database utilizzato dall'applicazione ha
FORCE ROW LEVEL SECURITYimpostato, in modo che nemmeno l'applicazione possa bypassare la politica senza cambiare ruolo.
Il risultato: un bug SQL nel tuo codebase non può far trapelare dati del tenant. Il database si rifiuta di restituire righe di altri tenant indipendentemente da cosa chieda la query. Abbiamo individuato bug reali in questo modo durante gli audit dei clienti — query che avrebbero restituito righe di altri tenant, bloccate da RLS, con un chiaro errore nei log.
Suggerimenti dalla nostra esperienza operativa:
- Usa un connection pooler (PgBouncer in modalità transaction-pooling) ma tieni presente che
SET LOCALsi azzera alla fine della transazione — questo è il comportamento corretto. - Per i background job, imposta
app.tenant_idnel job handler, non fidarti mai del solo payload del job. - Aggiungi un smoke test nella CI che tenti intenzionalmente di leggere la riga di un altro tenant e affermi che vengono restituite 0 righe.
- Gli indici compositi dovrebbero iniziare con
tenant_id— es.,(tenant_id, created_at)— per la stabilità del piano di esecuzione.
Schema-per-tenant — l'upgrade enterprise
Quando inizi a perdere contratti enterprise per via di «i miei dati sono nello stesso database di tutti gli altri?», schema-per-tenant è il passo successivo. Ogni tenant ottiene il proprio schema Postgres (tenant_a1b2c3) con il set completo di tabelle. L'applicazione imposta search_path all'inizio della transazione.
Vantaggi rispetto allo schema condiviso:
- Isolamento vero a livello di schema. Un bug non può restituire le righe di un altro tenant.
- Backup/restore per tenant più semplice (dump di un singolo schema).
- Eliminazione per tenant più semplice (singolo
DROP SCHEMA CASCADE). - Risposta favorevole agli auditor: «ogni tenant ha uno schema logicamente separato».
Costi:
- Le migrazioni devono essere eseguite su N schemi, in parallelo, con una corretta gestione dei guasti. Strumenti: Sqitch, Flyway o un orchestratore personalizzato.
- Le query analitiche cross-tenant diventano scomode (non puoi facilmente «fare SUM su tutti i tenant»). Risolvi con un database di analytics separato alimentato da CDC.
- La dimensione del catalogo Postgres cresce con N tenant × N tabelle. Oltre ~2.000 schemi, inizi a vedere il bloat di
pg_classche influisce sul tempo del planner.
Database-per-tenant — regolamentato e isolato
Per i settori regolamentati (HealthTech, GovTech, difesa, alcuni carichi di lavoro finanziari) e per i clienti «whale» che pagano 100.000+ USD/anno, assegna a ogni tenant il proprio database. Spesso il proprio VPC e la propria regione.
È costoso: 25–150 USD/mese per tenant su AWS RDS o equivalente. La giustificazione è che l'argomento per l'audit diventa banale, il raggio d'azione di qualsiasi bug è un singolo cliente, e i clienti che firmano contratti a sei cifre pagheranno per l'isolamento.
Dal punto di vista operativo hai bisogno di:
- Una pipeline IaC (Terraform, Pulumi) che effettua il provisioning di un nuovo database, esegue le migrazioni, configura i backup e connette l'osservabilità per ogni nuovo tenant.
- Un layer di routing dei tenant (tipicamente un Cloudflare Worker, un API gateway o un router basato su sottodominio nell'app) che mappa l'ID tenant sulla stringa di connessione al database.
- Un connection pool per tenant, con un sensato idle-eviction.
- Un flusso di deprovisioning robusto — eliminazione del database, archiviazione del suo backup e rimozione pulita del suo stato IaC.
Auth e identità su larga scala
Nel 2026 non c'è un buon motivo per costruire la propria auth multi-tenant. Le opzioni gestite hanno tutte convergito sullo stesso set di funzionalità:
| Provider | Punti di forza | Attenzione a |
|---|---|---|
| Clerk | Migliore DX, primitiva organizations, SDK per Next/Remix/Expo | Il prezzo scala molto oltre i 10.000 MAU |
| WorkOS | SSO enterprise (SAML/OIDC), SCIM, log di audit | UI di auth consumer meno raffinata |
| Auth0 | Maturo, esiste ogni integrazione | Costoso su larga scala; primitiva tenant complessa |
| Supabase Auth | Gratuito con Supabase; si abbina a Postgres RLS | Modello org/tenant è fai-da-te |
| FusionAuth / Keycloak | Self-host, compatibile con GDPR | Devi gestirlo tu |
Pattern comune nel 2026: Clerk o Supabase per la fase iniziale; aggiungi WorkOS al livello business per SSO/SCIM enterprise. La verifica del token al layer API estrae l'ID tenant e il ruolo dell'utente; il request handler imposta il GUC di Postgres.
Billing, misurazione e riconciliazione
Un Stripe Customer per tenant. I tenant si collegano ai Stripe customer tramite uno stripe_customer_id memorizzato. Le Subscription sono gestite in Stripe Billing. Per i componenti basati sull'utilizzo:
- Emetti eventi di utilizzo dall'applicazione verso un event bus (SNS, Kafka, NATS) taggato con ID tenant, nome del contatore, quantità, chiave di idempotenza.
- Un worker aggrega l'utilizzo per tenant nel tuo libro contabile interno (tabella Postgres).
- Un job di riconciliazione viene eseguito ogni notte, invia i delta a Stripe Meters (o Orb/Metronome/Lago) e scrive un report di riconciliazione giornaliero.
- Mostra l'utilizzo ai clienti nel prodotto — in tempo reale, con al massimo 60 secondi di ritardo. I clienti non si fideranno di una fattura opaca.
Abbiamo trattato il lato strategico dei prezzi in Modelli di pricing SaaS nel 2026; questo è il lato ingegneristico. Prevedi 6–10 settimane per un billing a misura di livello produzione — non due.
Residenza dei dati nell'UE nel modo corretto
Se vendi nell'UE (specialmente nei settori regolamentati o nel settore pubblico), «i dati rimangono nell'UE» è una casella da spuntare negli acquisti, non una dichiarazione di marketing. L'architettura corretta:
- Due cluster separati:
us-east-1eeu-central-1(o eu-west-1 per l'Irlanda, eu-north-1 per la Svezia). - Ogni cluster ha il proprio Postgres, blob storage, code, ricerca, stack di osservabilità.
- Mappatura tenant-cluster in un piccolo registro globale. Il flusso di login reindirizza all'API regionale corretta.
- Il provider di auth deve supportare la residenza nell'UE (Clerk EU, WorkOS EU, Auth0 EU tenant).
- Il fornitore di osservabilità deve supportare l'UE (Datadog EU, Sentry EU, Grafana Cloud EU).
- Non dividere le righe in un singolo database per regione — gli auditor non lo accettano.
Se costruisci con funzionalità IA, considera anche la regione del provider LLM: Anthropic offre endpoint EU; Bedrock supporta eu-central-1 per Claude; Azure OpenAI offre regioni EU per GPT-4o. Vedi la nostra pagina di conformità EU AI Act per il lato documentazione.
Osservabilità e SLO per tenant
Nel SaaS multi-tenant, «l'API è lenta» è privo di significato senza una suddivisione per tenant. Aggiungi l'ID tenant come dimensione di prima classe a ogni metrica, log e trace:
- Trace OpenTelemetry con attributo
tenant.idsu ogni span. - Tag Sentry
tenant_idsu ogni errore. - Dashboard Datadog/Grafana che suddividono per tenant la latenza p50/p95/p99 e il tasso di errore.
- Report dei 10 tenant più rumorosi — giornaliero, automatizzato.
- SLO per tenant per i tuoi top 20 account. Quando il loro budget SLO è a rischio, avvisa il loro CSM, non solo l'ingegneria.
Senza osservabilità per tenant, un singolo tenant enterprise rumoroso che degrada il p95 sembra un incidente globale. Con essa, puoi chiamare il cliente prima.
Percorsi di migrazione e insidie
Prima o poi migri. Due percorsi reali che abbiamo realizzato:
- Schema condiviso → schema-per-tenant. Fattibile ma doloroso. I nuovi tenant arrivano su schema-per-tenant; i tenant esistenti migrano in batch tramite dual-write + verifica + cutover. Prevedi 6–14 settimane di ingegneria per una migrazione di 500 tenant.
- Singola regione → multi-regione (residenza nell'UE). Costruisci prima il cluster UE, instrada i nuovi clienti UE verso di esso, migra i clienti UE esistenti tramite export + import + cutover con una finestra di manutenzione. 8–16 settimane.
Insidie che abbiamo incontrato ripetutamente:
- UUID senza v7. Gli UUID casuali (v4) danneggiano gli indici B-tree. Usa UUID v7 (time-ordered) per tutte le nuove chiavi primarie.
- tenant_id mancante nelle tabelle di supporto. Log di audit, allegati, record di consegna webhook — hanno tutti bisogno di tenant_id e di RLS.
- Tenant di lunga data con dati gonfiati. Un tenant con 10 milioni di righe in una tabella dove la mediana è 5.000 rallenta tutti tramite i buffer condivisi. Spostalo su schema-per-tenant o DB-per-tenant.
- Deriva del cliente Stripe. Un'eliminazione del tenant che non cancella le Stripe Subscription lascia revenue zombie e problemi contabili.
- Perdita nei background job. Un job attivato per il tenant A che interroga il tenant B perché il job runner ha dimenticato di impostare il GUC. Imposta sempre il GUC all'interno del job handler, non fidarti mai del payload.
FAQ
Qual è la migliore strategia di isolamento dei tenant per un nuovo SaaS?
Schema condiviso + Postgres RLS, con tenant_id su ogni tabella e il GUC impostato per richiesta. Il più facile da gestire, il meno costoso da scalare, il più facile da migrare in seguito.
Come gestisco l'auth in un SaaS multi-tenant?
Usa un provider gestito (Clerk, Auth0, WorkOS, Supabase Auth). Aggiungi WorkOS per SSO/SCIM enterprise al livello business.
Dove deve trovarsi il tenant_id nel modello dati?
In ogni tabella, indicizzato, con chiave esterna, applicato da RLS. Sempre.
Come gestisco la residenza dei dati nell'UE?
Cluster UE e USA separati con i propri database, storage e osservabilità. Instrada per tenant. Non dividere le righe all'interno di un singolo database.
Runtime serverless o container?
Container (Fargate, GKE Autopilot, Fly.io) per l'API principale; serverless per gli edge come webhook ed elaborazione delle immagini.
Come gestisco il billing su più tenant in modo pulito?
Un Stripe Customer per tenant, Subscription collegate al tenant_id interno, eventi a misura tramite Stripe Meters o Orb/Metronome. Riconcilia ogni notte.
Costruiscilo correttamente fin dall'inizio
Descrivici il tuo modello di tenancy, le esigenze di isolamento e l'argomento per gli audit. Ti diremo l'architettura meno costosa che sopravvive a una crescita di 100×.
Ultimo aggiornamento: 26 maggio 2026.


