Firebase Firestore è un database NoSQL cloud in tempo reale di Google, progettato per applicazioni mobili e web. Memorizza i dati in collezioni e documenti con sincronizzazione automatica tra i client. Secondo la documentazione Firebase, 2025, Firestore supporta il deployment multiregionale con consistenza forte e fornisce scaling automatico senza necessità di gestire i server. Il database si integra con Firebase Authentication e Cloud Functions per costruire un backend completo senza infrastruttura server propria.
Punti chiave
Firebase Firestore è un database NoSQL flessibile e scalabile lanciato da Google nel 2019 come evoluzione di Firebase Realtime Database. Memorizza i dati in collezioni di documenti, dove ogni documento contiene un insieme di coppie chiave-valore. A differenza dei database relazionali tradizionali, Firestore non richiede uno schema predefinito — la struttura dei dati si forma dinamicamente in base ai documenti scritti.
La differenza principale tra Firestore e i database cloud classici è la sincronizzazione integrata in tempo reale. Quando i dati cambiano sul server, tutti i client connessi ricevono aggiornamenti attraverso una connessione WebSocket persistente. Questo elimina la necessità di polling manuale del server e consente di costruire applicazioni con aggiornamenti live: chat, feed di attività, editor collaborativi e sistemi di monitoraggio.
Il database è disponibile su tutte le principali piattaforme: Android, iOS, Web (JavaScript) e linguaggi lato server tramite Admin SDK. Firestore fornisce SDK per Swift, Kotlin, JavaScript, Python, Go, Java e Node.js. Secondo Google, Firestore elabora oltre 100 miliardi di richieste al giorno in tutto l'ecosistema Firebase, confermando la sua affidabilità come base per applicazioni in produzione.
In Firestore, i dati sono organizzati in una struttura gerarchica. Una collezione è un contenitore di documenti, simile a una tabella in SQL ma senza schema fisso. Un documento è un record contenente campi di vario tipo: stringhe, numeri, valori booleani, array, oggetti annidati e geolocalizzazioni. I documenti possono contenere sottocollezioni, consentendo di costruire strutture dati annidate di qualsiasi profondità.
val db = FirebaseFirestore.getInstance()
val user = hashMapOf(
"name" to "Anna Petrova",
"email" to "anna@example.com",
"age" to 28,
"isActive" to true
)
db.collection("users")
.add(user)
.addOnSuccessListener { docRef ->
Log.d("TAG", "Documento aggiunto con ID: ${docRef.id}")
}
Ogni documento in una collezione ha un identificatore univoco, che può essere generato automaticamente o impostato manualmente. Firestore indicizza automaticamente tutti i campi del documento, consentendo query complesse con filtraggio, ordinamento e limitazione dei risultati senza configurazione manuale degli indici.
Firestore e Firebase Realtime Database sono due database cloud in tempo reale di Google. Sebbene entrambi forniscano sincronizzazione in tempo reale, hanno differenze fondamentali nel modello dati, nello scaling e nei prezzi. Comprendere queste differenze è cruciale nella scelta del database giusto per un progetto specifico.
| Caratteristica | Firestore | Realtime Database |
|---|---|---|
| Modello dati | Collezioni e documenti | Albero JSON singolo |
| Consistenza | Consistenza forte | Consistenza eventuale |
| Query | Composte con filtraggio e ordinamento | Solo filtraggio per un parametro |
| Scaling | Automatico, multiregionale | Regione singola, fino a 200k connessioni |
| Prezzi | Per operazioni di lettura/scrittura/eliminazione | Per volume di dati trasferiti |
La principale differenza architetturale è il modello dati. Realtime Database memorizza tutto in un grande albero JSON, complicando le query con annidamenti profondi. Firestore utilizza collezioni e documenti, consentendo query complesse con condizioni multiple. Inoltre, Firestore fornisce una forte consistenza dei dati: dopo una scrittura riuscita, tutte le letture successive garantiscono di restituire i dati più recenti.
Firestore scala automaticamente a milioni di connessioni simultanee grazie alla sua architettura multiregionale. Realtime Database è limitato a una singola regione e un massimo di 200.000 connessioni simultanee. Per progetti con pubblico globale, Firestore è preferibile poiché i dati vengono automaticamente replicati tra più data center Google.
La struttura dati in Firestore consente di costruire modelli gerarchici complessi con sottocollezioni. Ad esempio, un utente può avere una sottocollezione "ordini" e ogni ordine una sottocollezione "articoli". In Realtime Database, un annidamento così profondo causa problemi di prestazioni durante le query, poiché viene caricato l'intero percorso dalla radice al nodo necessario.
Firestore utilizza una connessione WebSocket persistente tra client e server per la sincronizzazione dei dati in tempo reale. Quando un'applicazione si sottoscrive alle modifiche di un documento o collezione tramite un snapshot listener, l'SDK stabilisce un canale di comunicazione attraverso il quale il server invia aggiornamenti ogni volta che i dati cambiano. Il client riceve solo i documenti modificati, non un'istantanea completa dell'intera collezione ogni volta.
Il meccanismo di sincronizzazione si basa su un flusso di eventi: added (documento apparso), modified (documento modificato) e removed (documento eliminato). Lo sviluppatore può gestire ogni evento separatamente, aggiornando solo gli elementi UI corrispondenti. Questo garantisce prestazioni elevate anche con migliaia di documenti, poiché vengono renderizzati nuovamente solo i componenti modificati.
Uno dei principali vantaggi di Firestore è il supporto integrato della modalità offline. L'SDK memorizza automaticamente nella cache tutti i dati letti sul dispositivo e continua a funzionare in assenza di rete. Quando l'applicazione scrive dati in modalità offline, vengono inseriti in una coda locale e inviati al server al ripristino della connessione. Per la risoluzione dei conflitti viene utilizzata la strategia last-write-wins.
val docRef = db.collection("cities").document("SF")
docRef.addSnapshotListener { snapshot, error ->
if (error != null) {
Log.w("TAG", "Errore di ascolto", error)
return@addSnapshotListener
}
if (snapshot != null && snapshot.exists()) {
Log.d("TAG", "Dati correnti: ${snapshot.data}")
}
}
La dimensione della cache può essere configurata tramite FirestoreSettings. Il valore predefinito è 100 MB, ma può essere aumentato per applicazioni con lettura intensiva dei dati. È disponibile anche una modalità cache su disco persistente che sopravvive ai riavvii dell'applicazione. Per gestire la disponibilità della modalità offline, vengono utilizzati i metodi enableNetwork e disableNetwork, che consentono di disabilitare temporaneamente l'interazione di rete.
Firestore Security Rules è un linguaggio di markup dichiarativo per controllare l'accesso ai dati a livello di server. Le regole definiscono chi può leggere e scrivere documenti e a quali condizioni. Funzionano prima dell'esecuzione della query e non richiedono logica server separata per l'autorizzazione. Le regole vengono verificate lato Firebase prima di ogni lettura o scrittura dei dati.
Le regole di accesso sono costruite sul principio di autorizzazione (allow). Per impostazione predefinita, tutto l'accesso è negato. Lo sviluppatore apre sequenzialmente l'accesso per operazioni specifiche (read, write, create, update, delete) a determinate condizioni. Le condizioni possono verificare l'autenticazione dell'utente tramite request.auth, i dati della richiesta tramite request.resource e i dati esistenti tramite resource.
// Regole di accesso Firestore
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// L'utente legge e scrive solo i propri dati
match /users/{userId} {
allow read, write: if
request.auth != null &&
request.auth.uid == userId;
}
// Qualsiasi utente autenticato può leggere i post
match /posts/{postId} {
allow read: if request.auth != null;
allow create: if request.auth != null
&& request.resource.data.author == request.auth.uid;
}
}
}
Oltre al controllo degli accessi, le Security Rules consentono di validare la struttura e i tipi dei dati scritti. Ad esempio, si può verificare che il campo email corrisponda a un'espressione regolare o che l'età non superi i 120 anni. La validazione viene eseguita prima della scrittura, impedendo il salvataggio di dati errati sul server. Per la validazione dei campi viene utilizzato l'oggetto request.resource.data contenente l'intero documento in fase di scrittura.
Firestore supporta anche collezioni accessibili solo per scrittura lato server tramite Admin SDK, senza accesso dai client. Questo è utile per memorizzare informazioni di servizio, chiavi API e configurazioni che non dovrebbero essere visibili agli utenti. Per farlo, è sufficiente negare tutte le operazioni client sulle collezioni corrispondenti nelle regole, consentendo l'accesso solo tramite Admin SDK dal lato server.
Vediamo un esempio di integrazione di Firestore in un'applicazione Android per creare una lista di attività (todo). L'applicazione leggerà le attività in tempo reale, ne aggiungerà di nuove e segnerà quelle completate. Per il lavoro asincrono vengono utilizzati i callback di Firebase e le coroutine Kotlin.
Prima di iniziare, è necessario collegare il progetto a Firebase tramite Firebase Console e aggiungere il file google-services.json al modulo dell'applicazione. Quindi, in build.gradle si aggiunge la dipendenza firebase-firestore-ktx e il plugin google-services. La versione della libreria deve corrispondere alla versione corrente di BoM Firebase per la compatibilità di tutti i componenti Firebase tra loro.
dependencies {
// Firebase BoM — gestione delle versioni
implementation platform("com.google.firebase:firebase-bom:33.0.0")
implementation "com.google.firebase:firebase-firestore-ktx"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0"
}
Dopo la configurazione, vengono creati un modello dati Task e un repository per lavorare con Firestore. Il modello contiene i campi id, title, isCompleted e timestamp. Firestore serializza automaticamente la data class in un documento, utilizzando i nomi dei campi come chiavi. Per leggere i dati viene utilizzato uno snapshot listener che restituisce un Flow tramite l'estensione snapshotFlow.
data class Task(
val id: String = "",
val title: String = "",
val isCompleted: Boolean = false,
val createdAt: Timestamp? = null
)
class TaskRepository {
private val tasksRef = FirebaseFirestore
.getInstance()
.collection("tasks")
fun getTasks(): Flow<List<Task>> = tasksRef
.orderBy("createdAt", Query.Direction.DESCENDING)
.snapshotFlow()
.map { snapshot ->
snapshot?.toObjects(Task::class.java) ?: emptyList()
}
suspend fun addTask(title: String) {
tasksRef.add(Task(title = title))
}
}
Il ViewModel si sottoscrive al Flow dal repository e passa l'elenco delle attività al livello UI. Quando viene aggiunta una nuova attività, la funzione suspend del repository viene chiamata tramite un ambito di coroutine. Firestore sincronizza automaticamente le modifiche tra tutti i client: se un utente aggiunge un'attività, gli altri la vedono in tempo reale senza ricaricare lo schermo.
Domande frequenti
Firestore è un database NoSQL con schema flessibile, senza tabelle e senza query JOIN. I dati sono memorizzati in collezioni di documenti, non in righe di tabelle. A differenza di SQL, Firestore non richiede uno schema predefinito e scala automaticamente senza migrazioni, ma non supporta query transazionali complesse tra collezioni.
Firestore ha un generoso limite gratuito (piano Spark): 50.000 letture, 20.000 scritture e 20.000 eliminazioni al giorno. Dopo il superamento, viene utilizzato il piano Blaze con pagamento a consumo: $0,06 per 100.000 letture e $0,18 per 100.000 scritture. Il prezzo dipende dalla regione e dal volume dei dati trasferiti.
Firestore utilizza la strategia last-write-wins per risolvere i conflitti: l'ultima scrittura su un documento sostituisce completamente la precedente. Per un controllo più preciso, sono disponibili transazioni (operazioni atomiche di lettura-scrittura) e scritture batch, che garantiscono l'integrità durante le operazioni su più documenti.
Sì, Firestore supporta l'esportazione e l'importazione dei dati tramite Firebase Console o gcloud CLI. L'esportazione viene eseguita in formato Cloud Firestore Export e salvata in Google Cloud Storage. I dati possono essere migrati tra progetti Firebase o esportati per l'analisi in BigQuery e altri strumenti.
Firestore non ha una ricerca full-text integrata. Per questo compito, Google raccomanda l'integrazione con Algolia o Meilisearch, o l'uso di Cloud Functions con Elasticsearch. Le query integrate di Firestore supportano solo controlli di uguaglianza, intervallo ed esistenza del campo senza ricerca per sottostringa.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche