Cos'è Supabase e come funziona
Cos'è Supabase e come funziona: backend pronto su PostgreSQL vero, con autenticazione, storage, API generate in automatico e Row Level Security spiegata bene.
Hai l'idea, hai il frontend che prende forma, e poi ti fermi sul solito muro: serve un database, serve il login, serve un posto dove caricare le immagini, serve un'API che tenga tutto insieme. Sono settimane di lavoro prima ancora di aver mostrato qualcosa a qualcuno. Supabase nasce per accorciare quel tratto. In questo articolo trovi cos'è davvero, come funziona ogni pezzo, e soprattutto qual è il concetto che devi capire bene per non farti male.
Cos'è
Supabase è un backend pronto all'uso costruito sopra un database PostgreSQL vero e proprio: ti dà database, autenticazione, storage dei file, funzioni e aggiornamenti in tempo reale, tutti già collegati tra loro e raggiungibili via API.
La parola importante in quella frase è vero. Supabase non ha inventato un database proprietario con un suo linguaggio e le sue regole: sotto c'è PostgreSQL, lo stesso che gireresti su una tua macchina. Il che significa una cosa molto concreta: i tuoi dati restano portabili. Se un giorno Supabase non ti va più bene, fai un dump del database e lo porti altrove. Tabelle, indici, vincoli, query: tutto continua a funzionare, perché è SQL standard.
Questo è il punto centrale del prodotto, ed è il motivo per cui vale la pena parlarne. Tutto il resto — l'interfaccia, le librerie, i servizi attorno — è comodità che si può ricostruire. La portabilità dei dati no.
Se non hai chiaro cosa sia un database in generale, parti da cos'è un database.
Cosa c'è dentro
Il database
Un'istanza PostgreSQL gestita, con un editor di tabelle nel browser per chi preferisce cliccare e un editor SQL per chi preferisce scrivere. Puoi usare le estensioni di Postgres, scrivere funzioni, definire vincoli e trigger. Non è un sottoinsieme edulcorato: è Postgres.
Le API generate automaticamente
Qui sta la comodità più evidente. Appena crei una tabella, hai già un'API REST per interrogarla. Non scrivi un endpoint, non definisci un controller, non c'è un file di rotte da mantenere.
import { createClient } from "@supabase/supabase-js";
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
);
// SELECT titolo, autore FROM articoli WHERE pubblicato = true
const { data, error } = await supabase
.from("articoli")
.select("titolo, autore")
.eq("pubblicato", true)
.order("creato_il", { ascending: false })
.limit(10);
Sotto, quella chiamata diventa una normale richiesta HTTP: è un'API REST come le altre, e puoi interrogarla con curl o da qualsiasi linguaggio. La libreria è solo una scorciatoia comoda.
Puoi anche seguire le relazioni tra tabelle in una sola chiamata, con select("titolo, autori ( nome, email )"). Se il concetto di API ti è ancora nebuloso, cos'è una API chiarisce le basi.
Autenticazione
Registrazione con email e password, login con link via email, accesso con Google, GitHub e altri provider, gestione delle sessioni e dei token. Gli utenti finiscono in una tabella auth.users dentro lo stesso database, quindi puoi collegarli ai tuoi dati con una normale chiave esterna.
Storage
Un servizio per caricare e servire file — immagini, allegati, avatar — organizzati in "bucket" pubblici o privati. Le regole di accesso si scrivono con lo stesso meccanismo usato per le tabelle, di cui parlo tra poco.
Funzioni
Due cose diverse con nomi simili, ed è bene distinguerle:
- Le funzioni Postgres, scritte in SQL o PL/pgSQL, girano dentro il database. Ottime per logica che deve stare vicina ai dati.
- Le Edge Function, che sono funzioni serverless in TypeScript. Servono per la logica che non può stare nel client: chiamare un servizio di pagamento con una chiave segreta, ricevere un webhook, elaborare qualcosa dopo un evento.
Realtime
Il client può sottoscriversi ai cambiamenti di una tabella e ricevere gli aggiornamenti mentre accadono, senza interrogare il server a intervalli.
È il pezzo che rende ragionevole costruire una chat, una dashboard che si aggiorna da sola o un documento condiviso senza montare un'infrastruttura dedicata.
Messi in fila, i pezzi coprono quello che altrimenti costruiresti a mano:
| Componente | Cosa ti dà | Cosa sostituisce |
|---|---|---|
| Database | PostgreSQL gestito | Un server con Postgres da amministrare |
| API automatiche | REST sopra ogni tabella | Il livello di endpoint scritto a mano |
| Auth | Login, provider esterni, sessioni | Registrazione e token fatti in casa |
| Storage | File con regole di accesso | Un bucket e la logica per servirlo |
| Edge Function | Codice lato server su richiesta | Un piccolo backend sempre acceso |
| Realtime | Aggiornamenti in tempo reale | Un server WebSocket dedicato |
Row Level Security: il concetto da capire bene
Qui serve fermarsi, perché è la parte che distingue chi usa Supabase bene da chi si trova con i dati esposti.
Il modello di Supabase è che il client parla direttamente al database. Non c'è un tuo server in mezzo che controlla chi sta chiedendo cosa. La chiave che metti nel frontend è pubblica per definizione: chiunque apra gli strumenti di sviluppo del browser la vede, e può usarla per fare le stesse chiamate che fa la tua applicazione.
Quindi la domanda diventa: cosa impedisce a un utente di leggere gli ordini di un altro?
La risposta è Row Level Security, una funzionalità di PostgreSQL: sono regole scritte nel database che decidono, riga per riga, chi può leggere e chi può scrivere. La sicurezza sta nel database, non nel client.
Il meccanismo ha due passaggi. Prima attivi RLS sulla tabella:
ALTER TABLE ordini ENABLE ROW LEVEL SECURITY;
Con RLS attiva e nessuna policy, la tabella diventa invisibile: nessuno legge niente. Poi definisci cosa è permesso:
-- ognuno vede solo i propri ordini
CREATE POLICY "leggi i miei ordini"
ON ordini FOR SELECT
USING (auth.uid() = utente_id);
-- e può creare ordini solo a proprio nome
CREATE POLICY "crea i miei ordini"
ON ordini FOR INSERT
WITH CHECK (auth.uid() = utente_id);
auth.uid() restituisce l'identificativo dell'utente autenticato, ricavato dal token della richiesta. Il confronto avviene dentro il database, dove il client non può metterci le mani.
Nota che SELECT, INSERT, UPDATE e DELETE sono operazioni separate: una policy di lettura non autorizza la scrittura. È corretto che sia così, ma va tenuto a mente.
Gli errori che fanno danni veri
Lasciare una tabella senza policy con RLS disattivata. È lo scenario peggiore, e capita più spesso di quanto si creda: crei una tabella dall'interfaccia mentre stai provando, non ti occupi delle policy perché "poi le metto", e quella tabella è leggibile da chiunque abbia la chiave pubblica — cioè da chiunque visiti il sito. Non serve un attacco: basta una richiesta HTTP. Regola: RLS attiva su ogni tabella esposta, sempre, dal primo minuto.
Scrivere una policy che sembra giusta ma non lo è. Una condizione come USING (true) su una tabella privata autorizza tutti. Una policy di UPDATE senza WITH CHECK può permettere a un utente di modificare una riga e nel farlo riassegnarla a qualcun altro. Le policy vanno provate come si prova il codice: accedi con due utenti diversi e verifica che ciascuno veda solo il suo.
Usare la chiave di servizio nel frontend. Supabase fornisce una chiave service_role che ignora completamente RLS: serve per script amministrativi e codice lato server. Se finisce in un bundle JavaScript, hai consegnato l'intero database. Sta in una variabile d'ambiente lato server e non si muove da lì — vedi variabili d'ambiente.
Mettere la logica di business solo nel client. Se il controllo "solo gli amministratori possono cancellare" vive in una funzione JavaScript, non esiste: chi chiama l'API direttamente lo salta. Deve stare in una policy o in una funzione lato server.
Sul tema più ampio, rendere sicuro un sito copre le abitudini di base.
Self-hosting
Supabase è open source, e puoi ospitarlo da solo. Il progetto distribuisce le immagini Docker di tutti i componenti, quindi puoi far girare tutto su un VPS tuo.
Va detto con onestà: gestirsi Supabase da soli significa amministrare Postgres, il servizio di autenticazione, lo storage, il gateway delle API e i backup. È fattibile e sensato se hai vincoli specifici — dati che non possono uscire da un certo confine, requisiti GDPR stringenti — ma non è "gratis": paghi in tempo quello che risparmi in fattura.
Il valore reale del self-hosting, per la maggior parte dei progetti, non è farlo davvero: è sapere di poterlo fare.
Il modello di prezzo
Supabase lavora a fasce: un piano gratuito con limiti pensato per provare, poi piani a canone mensile per progetto, con supplementi oltre certe soglie.
Non ti do cifre perché cambiano, ma il punto strutturale conta più dei numeri: è un modello prevedibile. Sai in anticipo cosa spendi in un mese normale, e una query scritta male non moltiplica la bolletta. Il piano gratuito, in genere, mette in pausa i progetti inattivi: va bene per un esperimento, meno per qualcosa che deve rispondere sempre.
Quando conviene e quando no
Conviene quando:
- I tuoi dati sono relazionali — utenti, ordini, contenuti collegati tra loro — cioè la forma della maggior parte delle applicazioni.
- Vuoi arrivare in fretta a un MVP funzionante senza costruire il backend da zero.
- Ti importa della portabilità: non vuoi che l'uscita sia impossibile.
- Conosci già SQL, o hai voglia di impararlo. Con Supabase è un investimento che si ripaga.
- Stai facendo un'applicazione web, dove le librerie e la documentazione sono più mature.
Conviene meno quando:
- Il team non conosce SQL e nessuno ha voglia di occuparsi delle policy RLS. Il modello richiede attenzione: senza, è pericoloso.
- Hai bisogni molto particolari sul backend che un'API generata non copre. Puoi comunque metterci un tuo server davanti, ma allora parte del vantaggio si perde.
- Il progetto è quasi solo mobile e vuoi l'ecosistema più rodato in quel campo — è un discorso che approfondisco in Supabase o Firebase.
In sintesi
Supabase è un backend pronto costruito su PostgreSQL vero, con database, autenticazione, storage, funzioni e realtime già collegati e già esposti come API.
Il vantaggio strutturale è la portabilità: sotto c'è SQL standard, quindi i dati restano tuoi e l'uscita è sempre possibile.
Il concetto da padroneggiare è Row Level Security: il client parla direttamente al database, quindi la sicurezza vive nelle policy. Una tabella senza policy corrette è una tabella pubblica, punto.
Il prezzo è a fasce, quindi prevedibile, il che è un dettaglio meno appariscente di quanto sembri quando arriva la fattura.
Per capire se è la scelta giusta rispetto all'alternativa più nota, leggi Supabase o Firebase e cos'è Firebase. Se stai ancora decidendo le fondamenta, scegliere lo stack per una web app è il passo prima di questo.