Access data offline

Note: Offline data can be accessed only using Core operations.

Cloud Firestore supports offline data persistence. This feature caches a copyof theCloud Firestore data that your app is actively using, so your appcan access the data when the device is offline. You can write, read, listen to,and query the cached data.

When the device comes back online,Cloud Firestore synchronizes any local changes made by your app to theCloud Firestore backend. For multiple changes to the same document,it's last write wins.

Note:

To use offline persistence, you don't need to make any changes to the code thatyou use to accessCloud Firestore data. With offline persistence enabled,theCloud Firestore client library automatically manages online andoffline data access and synchronizes local data when the device is back online.

Configure offline persistence

When you initializeCloud Firestore, you can enable or disableoffline persistence:

  • For Android and Apple platforms, offline persistence is enabled by default. To disablepersistence, set thePersistenceEnabled option tofalse.
  • For the web, offline persistence is disabled by default. To enablepersistence, call theenablePersistence method.Cloud Firestore's cacheisn't automatically cleared between sessions. Consequently, if your web apphandles sensitive information, make sure to ask the user if they're on a trusteddevice before enabling persistence.
Important: For the web, offline persistence is supported only by the Chrome,Safari, and Firefox web browsers.

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
// Memory cache is the default if no config is specified.initializeFirestore(app);// This is the default behavior if no persistence is specified.initializeFirestore(app,{localCache:memoryLocalCache()});// Defaults to single-tab persistence if no tab manager is specified.initializeFirestore(app,{localCache:persistentLocalCache(/*settings*/{})});// Same as `initializeFirestore(app, {localCache: persistentLocalCache(/*settings*/{})})`,// but more explicit about tab management.initializeFirestore(app,{localCache:persistentLocalCache(/*settings*/{tabManager:persistentSingleTabManager()})});// Use multi-tab IndexedDb persistence.initializeFirestore(app,{localCache:persistentLocalCache(/*settings*/{tabManager:persistentMultipleTabManager()})});

Web

Learn more about the tree-shakeable Web v9 modular SDK andupgrade from version 8.
firebase.firestore().enablePersistence().catch((err)=>{if(err.code=='failed-precondition'){// Multiple tabs open, persistence can only be enabled// in one tab at a a time.// ...}elseif(err.code=='unimplemented'){// The current browser does not support all of the// features required to enable persistence// ...}});// Subsequent queries will use persistence, if it was enabled successfully
Swift
Note: This product is not available on watchOS and App Clip targets.
letsettings=FirestoreSettings()// Use memory-only cachesettings.cacheSettings=MemoryCacheSettings(garbageCollectorSettings:MemoryLRUGCSettings())// Use persistent disk cache, with 100 MB cache sizesettings.cacheSettings=PersistentCacheSettings(sizeBytes:100*1024*1024asNSNumber)// Any additional options// ...// Enable offline data persistenceletdb=Firestore.firestore()db.settings=settings
Objective-C
Note: This product is not available on watchOS and App Clip targets.
FIRFirestoreSettings*settings=[[FIRFirestoreSettingsalloc]init];// Use memory-only cachesettings.cacheSettings=[[FIRMemoryCacheSettingsalloc]initWithGarbageCollectorSettings:[[FIRMemoryLRUGCSettingsalloc]init]];// Use persistent disk cache (default behavior)// This example uses 100 MB.settings.cacheSettings=[[FIRPersistentCacheSettingsalloc]initWithSizeBytes:@(100*1024*1024)];// Any additional options// ...// Enable offline data persistenceFIRFirestore*db=[FIRFirestorefirestore];db.settings=settings;

Kotlin

valsettings=firestoreSettings{// Use memory cachesetLocalCacheSettings(memoryCacheSettings{})// Use persistent disk cache (default)setLocalCacheSettings(persistentCacheSettings{})}db.firestoreSettings=settings

Java

FirebaseFirestoreSettingssettings=newFirebaseFirestoreSettings.Builder(db.getFirestoreSettings())// Use memory-only cache.setLocalCacheSettings(MemoryCacheSettings.newBuilder().build())// Use persistent disk cache (default).setLocalCacheSettings(PersistentCacheSettings.newBuilder().build()).build();db.setFirestoreSettings(settings);

Dart

// Apple and Androiddb.settings=constSettings(persistenceEnabled:true);// Webawaitdb.enablePersistence(constPersistenceSettings(synchronizeTabs:true));

Configure cache size

When persistence is enabled,Cloud Firestore caches every documentreceived from the backend for offline access.Cloud Firestore sets adefault threshold for cache size. After exceeding the default,Cloud Firestore periodically attempts to clean up older, unuseddocuments. You can configure a different cache size thresholdor disable the clean-up process completely:

Web

import{initializeFirestore,CACHE_SIZE_UNLIMITED}from"firebase/firestore";constfirestoreDb=initializeFirestore(app,{cacheSizeBytes:CACHE_SIZE_UNLIMITED});

Web

Learn more about the tree-shakeable modular Web API and its advantages over the namespaced API.
firebase.firestore().settings({cacheSizeBytes:firebase.firestore.CACHE_SIZE_UNLIMITED});
Swift
Note: This product is not available on watchOS and App Clip targets.
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes"// for a different threshold (minimum 1 MB) or set to "FirestoreCacheSizeUnlimited"// to disable clean-up.letsettings=Firestore.firestore().settings// Set cache size to 100 MBsettings.cacheSettings=PersistentCacheSettings(sizeBytes:100*1024*1024asNSNumber)Firestore.firestore().settings=settings
Objective-C
Note: This product is not available on watchOS and App Clip targets.
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes"// for a different threshold (minimum 1 MB) or set to "kFIRFirestoreCacheSizeUnlimited"// to disable clean-up.FIRFirestoreSettings*settings=[FIRFirestorefirestore].settings;// Set cache size to 100 MBsettings.cacheSettings=[[FIRPersistentCacheSettingsalloc]initWithSizeBytes:@(100*1024*1024)];[FIRFirestorefirestore].settings=settings;

Kotlin

// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes"// for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED"// to disable clean-up.valsettings=FirebaseFirestoreSettings.Builder().setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED).build()db.firestoreSettings=settings

Java

// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes"// for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED"// to disable clean-up.FirebaseFirestoreSettingssettings=newFirebaseFirestoreSettings.Builder().setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED).build();db.setFirestoreSettings(settings);

Dart

db.settings=constSettings(persistenceEnabled:true,cacheSizeBytes:Settings.CACHE_SIZE_UNLIMITED,);

Listen to offline data

While the device is offline, if you have enabled offline persistence, yourlisteners will receive listen events when the locally cached data changes. Youcan listen to documents, collections, and queries.

To check whether you're receiving data from the server or the cache, use thefromCache property on theSnapshotMetadata in your snapshot event. IffromCache istrue, the data came from the cache and might be stale orincomplete. IffromCache isfalse, the data is complete and current with thelatest updates on the server.

By default, no event is raised ifonly theSnapshotMetadata changed. If yourely on thefromCache values, specify theincludeMetadataChanges listenoption when you attach your listen handler.

Web

import{collection,onSnapshot,where,query}from"firebase/firestore";constq=query(collection(db,"cities"),where("state","==","CA"));onSnapshot(q,{includeMetadataChanges:true},(snapshot)=>{snapshot.docChanges().forEach((change)=>{if(change.type==="added"){console.log("New city: ",change.doc.data());}constsource=snapshot.metadata.fromCache?"local cache":"server";console.log("Data came from "+source);});});

Web

Learn more about the tree-shakeable modular Web API and its advantages over the namespaced API.
db.collection("cities").where("state","==","CA").onSnapshot({includeMetadataChanges:true},(snapshot)=>{snapshot.docChanges().forEach((change)=>{if(change.type==="added"){console.log("New city: ",change.doc.data());}varsource=snapshot.metadata.fromCache?"local cache":"server";console.log("Data came from "+source);});});
Swift
Note: This product is not available on watchOS and App Clip targets.
// Listen to metadata updates to receive a server snapshot even if// the data is the same as the cached data.db.collection("cities").whereField("state",isEqualTo:"CA").addSnapshotListener(includeMetadataChanges:true){querySnapshot,erroringuardletsnapshot=querySnapshotelse{print("Error retreiving snapshot:\(error!)")return}fordiffinsnapshot.documentChanges{ifdiff.type==.added{print("New city:\(diff.document.data())")}}letsource=snapshot.metadata.isFromCache?"local cache":"server"print("Metadata: Data fetched from\(source)")}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
// Listen to metadata updates to receive a server snapshot even if// the data is the same as the cached data.[[[dbcollectionWithPath:@"cities"]queryWhereField:@"state"isEqualTo:@"CA"]addSnapshotListenerWithIncludeMetadataChanges:YESlistener:^(FIRQuerySnapshot*snapshot,NSError*error){if(snapshot==nil){NSLog(@"Error retreiving snapshot: %@",error);return;}for(FIRDocumentChange*diffinsnapshot.documentChanges){if(diff.type==FIRDocumentChangeTypeAdded){NSLog(@"New city: %@",diff.document.data);}}NSString*source=snapshot.metadata.isFromCache?@"local cache":@"server";NSLog(@"Metadata: Data fetched from %@",source);}];

Kotlin

db.collection("cities").whereEqualTo("state","CA").addSnapshotListener(MetadataChanges.INCLUDE){querySnapshot,e->if(e!=null){Log.w(TAG,"Listen error",e)return@addSnapshotListener}for(changeinquerySnapshot!!.documentChanges){if(change.type==DocumentChange.Type.ADDED){Log.d(TAG,"New city: ${change.document.data}")}valsource=if(querySnapshot.metadata.isFromCache){"local cache"}else{"server"}Log.d(TAG,"Data fetched from $source")}}

Java

db.collection("cities").whereEqualTo("state","CA").addSnapshotListener(MetadataChanges.INCLUDE,newEventListener<QuerySnapshot>(){@OverridepublicvoidonEvent(@NullableQuerySnapshotquerySnapshot,@NullableFirebaseFirestoreExceptione){if(e!=null){Log.w(TAG,"Listen error",e);return;}for(DocumentChangechange:querySnapshot.getDocumentChanges()){if(change.getType()==Type.ADDED){Log.d(TAG,"New city:"+change.getDocument().getData());}Stringsource=querySnapshot.getMetadata().isFromCache()?"local cache":"server";Log.d(TAG,"Data fetched from "+source);}}});

Dart

db.collection("cities").where("state",isEqualTo:"CA").snapshots(includeMetadataChanges:true).listen((querySnapshot){for(varchangeinquerySnapshot.docChanges){if(change.type==DocumentChangeType.added){finalsource=(querySnapshot.metadata.isFromCache)?"local cache":"server";print("Data fetched from$source}");}}});

Get offline data

If you get a document while the device is offline,Cloud Firestorereturns data from the cache.

When querying a collection, an empty result is returned if there are no cacheddocuments. When fetching a specific document, an error is returned instead.

Query offline data

Querying works with offline persistence. You can retrieve the results of querieswith either a direct get or by listening, as described in the precedingsections. You can also create new queries on locally persisted data while thedevice is offline, but the queries will initially run only against the cacheddocuments.

Configure offline query indexes

By default, the Firestore SDK scans all documents in a collection in its local cache when executing offline queries. With this default behavior, offlinequery performance can suffer when users are offline for long periods of time.

With persistent cache enabled, you can improve the performance of offlinequeries by allowing the SDK to create local query indexes automatically.

Automatic indexing is disabled by default. Your app must enableautomatic indexing each time it starts. Control whether automatic indexing isenabled as shown below.

Swift
ifletindexManager=Firestore.firestore().persistentCacheIndexManager{// Indexing is disabled by defaultindexManager.enableIndexAutoCreation()}else{print("indexManager is nil")}
Objective-C
PersistentCacheIndexManager*indexManager=[FIRFirestorefirestore].persistentCacheIndexManager;if(indexManager){// Indexing is disabled by default[indexManagerenableIndexAutoCreation];}

Kotlin

// return type: PersistentCacheManager?Firebase.firestore.persistentCacheIndexManager?.apply{// Indexing is disabled by defaultenableIndexAutoCreation()}?:println("indexManager is null")

Java

// return type: @Nullable PersistentCacheIndexManagerPersistentCacheIndexManagerindexManager=FirebaseFirestore.getInstance().getPersistentCacheIndexManager();if(indexManager!=null){// Indexing is disabled by defaultindexManager.enableIndexAutoCreation();}// If not check indexManager != null, IDE shows warning: Method invocation 'enableIndexAutoCreation' may produce 'NullPointerException'FirebaseFirestore.getInstance().getPersistentCacheIndexManager().enableIndexAutoCreation();

Once automatic indexing is enabled, the SDK evaluates which collections havea large number of cached documents and optimizes performance of local queries.

The SDK provides a method for deleting query indexes.

Disable and enable network access

You can use the method below to disable network access for yourCloud Firestore client. While network access is disabled, all snapshotlisteners and document requests retrieve results from the cache. Writeoperations are queued until network access is re-enabled.

Web

import{disableNetwork}from"firebase/firestore";awaitdisableNetwork(db);console.log("Network disabled!");// Do offline actions// ...

Web

Learn more about the tree-shakeable modular Web API and its advantages over the namespaced API.
firebase.firestore().disableNetwork().then(()=>{// Do offline actions// ...});
Swift
Note: This product is not available on watchOS and App Clip targets.
Firestore.firestore().disableNetwork{(error)in// Do offline things// ...}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
[[FIRFirestorefirestore]disableNetworkWithCompletion:^(NSError*_Nullableerror){// Do offline actions// ...}];

Kotlin

db.disableNetwork().addOnCompleteListener{// Do offline things// ...}

Java

db.disableNetwork().addOnCompleteListener(newOnCompleteListener<Void>(){@OverridepublicvoidonComplete(@NonNullTask<Void>task){// Do offline things// ...}});

Dart

db.disableNetwork().then((_){// Do offline things});

Use the following method to re-enable network access:

Web

import{enableNetwork}from"firebase/firestore";awaitenableNetwork(db);// Do online actions// ...

Web

Learn more about the tree-shakeable modular Web API and its advantages over the namespaced API.
firebase.firestore().enableNetwork().then(()=>{// Do online actions// ...});
Swift
Note: This product is not available on watchOS and App Clip targets.
Firestore.firestore().enableNetwork{(error)in// Do online things// ...}
Objective-C
Note: This product is not available on watchOS and App Clip targets.
[[FIRFirestorefirestore]enableNetworkWithCompletion:^(NSError*_Nullableerror){// Do online actions// ...}];

Kotlin

db.enableNetwork().addOnCompleteListener{// Do online things// ...}

Java

db.enableNetwork().addOnCompleteListener(newOnCompleteListener<Void>(){@OverridepublicvoidonComplete(@NonNullTask<Void>task){// Do online things// ...}});

Dart

db.enableNetwork().then((_){// Back online});

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-18 UTC.