React Native Firebase Cloud Firestore provides a NoSQL document database with real-time synchronization capabilities.
—
Comprehensive offline support with configurable persistence, network management, and cache control.
Manage network connectivity to control when Firestore communicates with the server.
/**
* Enable network connectivity for Firestore
* @returns Promise resolving when network is enabled
*/
enableNetwork(): Promise<void>;
/**
* Disable network connectivity for Firestore
* @returns Promise resolving when network is disabled
*/
disableNetwork(): Promise<void>;Usage Examples:
import firestore from '@react-native-firebase/firestore';
// Enable network (default state)
await firestore().enableNetwork();
console.log('Network enabled - can sync with server');
// Disable network for offline-only operation
await firestore().disableNetwork();
console.log('Network disabled - operating in offline mode');
// Re-enable network
await firestore().enableNetwork();
console.log('Network re-enabled - will sync pending changes');
// Network state management based on app state
import { AppState } from 'react-native';
class NetworkManager {
constructor() {
AppState.addEventListener('change', this.handleAppStateChange);
}
handleAppStateChange = async (nextAppState: string) => {
const db = firestore();
if (nextAppState === 'background') {
// Disable network to save battery/data when app is backgrounded
await db.disableNetwork();
console.log('App backgrounded - network disabled');
} else if (nextAppState === 'active') {
// Re-enable network when app becomes active
await db.enableNetwork();
console.log('App active - network enabled');
}
};
}Control offline data persistence and cache behavior.
/**
* Clear all cached data and pending writes
* @returns Promise resolving when persistence is cleared
*/
clearPersistence(): Promise<void>;
/**
* Wait for all pending writes to complete
* @returns Promise resolving when all writes are committed
*/
waitForPendingWrites(): Promise<void>;
/**
* Terminate the Firestore instance and clean up resources
* @returns Promise resolving when termination is complete
*/
terminate(): Promise<void>;Usage Examples:
import firestore from '@react-native-firebase/firestore';
// Clear all cached data (useful for user logout)
async function clearUserData() {
const db = firestore();
// First disable network to prevent new data
await db.disableNetwork();
// Clear all cached data
await db.clearPersistence();
console.log('All cached data cleared');
// Re-enable network for fresh start
await db.enableNetwork();
}
// Wait for pending writes before performing sensitive operations
async function performSecureOperation() {
const db = firestore();
// Ensure all pending writes are committed
await db.waitForPendingWrites();
console.log('All writes committed to server');
// Now safe to perform secure operation
await performSensitiveTask();
}
// Clean shutdown of Firestore
async function shutdownFirestore() {
const db = firestore();
// Wait for pending operations
await db.waitForPendingWrites();
// Terminate the instance
await db.terminate();
console.log('Firestore instance terminated');
}
// Handle app lifecycle for proper cleanup
class FirestoreManager {
async componentWillUnmount() {
try {
// Ensure data is persisted before app closes
await firestore().waitForPendingWrites();
} catch (error) {
console.error('Error waiting for writes:', error);
}
}
}Configure Firestore behavior including cache size, persistence, and server settings.
/**
* Configure Firestore settings
* @param settings - Configuration options
* @returns Promise resolving when settings are applied
*/
settings(settings: FirebaseFirestoreTypes.Settings): Promise<void>;
interface Settings {
/**
* Enable or disable offline persistence
* @default true
*/
persistence?: boolean;
/**
* Cache size in bytes (-1 for unlimited)
* @default 104857600 (100 MB)
*/
cacheSizeBytes?: number;
/**
* Firestore host (for custom endpoints)
*/
host?: string;
/**
* Enable or disable SSL
* @default true
*/
ssl?: boolean;
/**
* Ignore undefined properties in document data
* @default false
*/
ignoreUndefinedProperties?: boolean;
/**
* Behavior for server timestamps that haven't been set yet
* @default 'none'
*/
serverTimestampBehavior?: 'estimate' | 'previous' | 'none';
}Usage Examples:
import firestore from '@react-native-firebase/firestore';
// Configure basic settings
await firestore().settings({
persistence: true,
cacheSizeBytes: 50 * 1024 * 1024, // 50 MB cache
ignoreUndefinedProperties: true
});
// Unlimited cache size
await firestore().settings({
cacheSizeBytes: firestore.CACHE_SIZE_UNLIMITED
});
// Custom server timestamp behavior
await firestore().settings({
serverTimestampBehavior: 'estimate' // Use local time estimate
});
// Development settings with custom host
await firestore().settings({
host: 'localhost:8080',
ssl: false,
persistence: false // Disable for development
});
// Production optimized settings
await firestore().settings({
persistence: true,
cacheSizeBytes: 100 * 1024 * 1024, // 100 MB
ignoreUndefinedProperties: true,
serverTimestampBehavior: 'estimate'
});
// Memory-constrained device settings
await firestore().settings({
persistence: true,
cacheSizeBytes: 10 * 1024 * 1024, // 10 MB cache
ignoreUndefinedProperties: true
});Connect to the Firestore emulator for development and testing.
/**
* Connect to Firestore emulator
* @param host - Emulator host
* @param port - Emulator port
* @returns Array containing actual host and port used (for testing)
*/
useEmulator(host: string, port: number): [string, number];Usage Examples:
import firestore from '@react-native-firebase/firestore';
// Connect to local emulator
if (__DEV__) {
// Connect to emulator running on localhost:8080
firestore().useEmulator('localhost', 8080);
console.log('Connected to Firestore emulator');
}
// Connect to emulator with custom configuration
if (__DEV__) {
const db = firestore();
// Use emulator
db.useEmulator('127.0.0.1', 8080);
// Configure for development
await db.settings({
persistence: false, // Disable persistence in development
cacheSizeBytes: 1024 * 1024 // 1 MB cache for testing
});
}
// Environment-based emulator configuration
const initializeFirestore = async () => {
const db = firestore();
if (process.env.NODE_ENV === 'development') {
// Development: use emulator
db.useEmulator('localhost', 8080);
await db.settings({
persistence: false,
ignoreUndefinedProperties: true
});
} else if (process.env.NODE_ENV === 'test') {
// Testing: use emulator with clean state
db.useEmulator('localhost', 8080);
await db.clearPersistence();
await db.settings({ persistence: false });
} else {
// Production: use real Firestore
await db.settings({
persistence: true,
cacheSizeBytes: 50 * 1024 * 1024,
ignoreUndefinedProperties: true
});
}
};Load pre-packaged data bundles for efficient initial data loading and execute pre-configured queries.
/**
* Load a data bundle containing documents and queries
* @param bundle - Bundle data as string
* @returns Promise resolving to load bundle task progress
*/
loadBundle(bundle: string): Promise<FirebaseFirestoreTypes.LoadBundleTaskProgress>;
/**
* Get a pre-configured query from a loaded bundle
* @param queryName - Name of the query in the bundle
* @returns Query instance or null if not found
*/
namedQuery(queryName: string): FirebaseFirestoreTypes.Query | null;
interface LoadBundleTaskProgress {
/**
* Number of documents loaded so far
*/
documentsLoaded: number;
/**
* Total number of documents in the bundle
*/
totalDocuments: number;
/**
* Number of bytes loaded so far
*/
bytesLoaded: number;
/**
* Total number of bytes in the bundle
*/
totalBytes: number;
/**
* Current task state
*/
taskState: FirebaseFirestoreTypes.TaskState;
}
type TaskState = 'Error' | 'Running' | 'Success';Usage Examples:
import firestore from '@react-native-firebase/firestore';
// Load a data bundle
async function loadInitialData() {
const db = firestore();
try {
// Bundle data (typically fetched from server or included in app)
const bundleData = await fetch('/api/firestore-bundle').then(r => r.text());
// Load the bundle
const progress = await db.loadBundle(bundleData);
console.log('Bundle loaded successfully:');
console.log(`Documents: ${progress.documentsLoaded}/${progress.totalDocuments}`);
console.log(`Bytes: ${progress.bytesLoaded}/${progress.totalBytes}`);
console.log(`Status: ${progress.taskState}`);
// Use named queries from the bundle
const featuredProductsQuery = db.namedQuery('featured-products');
if (featuredProductsQuery) {
const snapshot = await featuredProductsQuery.get();
console.log(`Found ${snapshot.size} featured products`);
}
} catch (error) {
console.error('Error loading bundle:', error);
}
}
// Progressive bundle loading with progress tracking
async function loadBundleWithProgress(bundleData: string) {
const db = firestore();
// Note: In practice, you might want to implement progress tracking
// This is a simplified example showing the final result
const progress = await db.loadBundle(bundleData);
if (progress.taskState === 'Success') {
console.log('Bundle loaded successfully');
// Access bundled queries
const popularQuery = db.namedQuery('popular-items');
const recentQuery = db.namedQuery('recent-activity');
if (popularQuery && recentQuery) {
const [popularResults, recentResults] = await Promise.all([
popularQuery.get(),
recentQuery.get()
]);
console.log('Popular items:', popularResults.size);
console.log('Recent activity:', recentResults.size);
}
} else if (progress.taskState === 'Error') {
console.error('Bundle loading failed');
}
}
// Offline-first app initialization with bundles
async function initializeOfflineApp() {
const db = firestore();
// Load cached bundle for immediate offline access
try {
const cachedBundle = await getCachedBundle(); // Your caching logic
if (cachedBundle) {
await db.loadBundle(cachedBundle);
console.log('Offline bundle loaded');
}
} catch (error) {
console.log('No cached bundle available');
}
// Try to load fresh bundle when online
try {
const freshBundle = await fetchFreshBundle(); // Your fetch logic
if (freshBundle) {
await db.loadBundle(freshBundle);
console.log('Fresh bundle loaded');
await cacheBundleForOffline(freshBundle);
}
} catch (error) {
console.log('Could not load fresh bundle, using cached version');
}
}Access and manage persistent cache index operations.
/**
* Get persistent cache index manager (null if persistence disabled)
* @returns PersistentCacheIndexManager instance or null
*/
persistentCacheIndexManager(): FirebaseFirestoreTypes.PersistentCacheIndexManager | null;
interface PersistentCacheIndexManager {
/**
* Enable automatic index creation for queries
* @returns Promise resolving when auto-creation is enabled
*/
enablePersistentCacheIndexAutoCreation(): Promise<void>;
/**
* Disable automatic index creation for queries
* @returns Promise resolving when auto-creation is disabled
*/
disablePersistentCacheIndexAutoCreation(): Promise<void>;
/**
* Delete all persistent cache indexes
* @returns Promise resolving when all indexes are deleted
*/
deleteAllPersistentCacheIndexes(): Promise<void>;
}Usage Examples:
import firestore from '@react-native-firebase/firestore';
// Manage cache indexes
async function manageCacheIndexes() {
const db = firestore();
const indexManager = db.persistentCacheIndexManager();
if (indexManager) {
// Enable automatic index creation
await indexManager.enablePersistentCacheIndexAutoCreation();
console.log('Auto index creation enabled');
// Later, if you need to clean up indexes
await indexManager.deleteAllPersistentCacheIndexes();
console.log('All cache indexes deleted');
// Disable auto creation
await indexManager.disablePersistentCacheIndexAutoCreation();
console.log('Auto index creation disabled');
} else {
console.log('Cache persistence is disabled - no index manager available');
}
}
// Initialize with index management
async function initializeWithCacheManagement() {
const db = firestore();
// Configure persistence
await db.settings({
persistence: true,
cacheSizeBytes: 100 * 1024 * 1024
});
// Manage indexes
const indexManager = db.persistentCacheIndexManager();
if (indexManager) {
await indexManager.enablePersistentCacheIndexAutoCreation();
}
}Best practices for working with offline data and handling connectivity changes.
Usage Examples:
import firestore from '@react-native-firebase/firestore';
import NetInfo from '@react-native-netinfo/netinfo';
class OfflineManager {
private isOnline = true;
private pendingWrites: Array<() => Promise<void>> = [];
constructor() {
this.setupNetworkListener();
this.setupFirestoreSettings();
}
private async setupFirestoreSettings() {
await firestore().settings({
persistence: true,
cacheSizeBytes: 50 * 1024 * 1024,
ignoreUndefinedProperties: true,
serverTimestampBehavior: 'estimate'
});
}
private setupNetworkListener() {
NetInfo.addEventListener(state => {
const wasOnline = this.isOnline;
this.isOnline = state.isConnected ?? false;
if (!wasOnline && this.isOnline) {
this.handleConnectionRestored();
} else if (wasOnline && !this.isOnline) {
this.handleConnectionLost();
}
});
}
private async handleConnectionRestored() {
console.log('Connection restored - syncing data');
try {
// Enable network
await firestore().enableNetwork();
// Wait for pending writes to sync
await firestore().waitForPendingWrites();
console.log('All data synced successfully');
} catch (error) {
console.error('Error syncing data:', error);
}
}
private async handleConnectionLost() {
console.log('Connection lost - operating offline');
// Firestore automatically handles offline mode
// No need to explicitly disable network
}
// Queue writes for when connection is restored
async queueWrite(writeOperation: () => Promise<void>) {
if (this.isOnline) {
await writeOperation();
} else {
this.pendingWrites.push(writeOperation);
console.log('Write queued for when connection is restored');
}
}
// Get data with source preference
async getData(docRef: firestore.DocumentReference, preferCache = false) {
try {
if (preferCache || !this.isOnline) {
// Try cache first
const cacheSnapshot = await docRef.get({ source: 'cache' });
if (cacheSnapshot.exists) {
return cacheSnapshot;
}
}
// Fall back to server
return await docRef.get({ source: 'server' });
} catch (error) {
// If server fails, try cache
return await docRef.get({ source: 'cache' });
}
}
}
// Usage with real-time listeners that handle offline state
const setupOfflineAwareListener = (docRef: firestore.DocumentReference) => {
return docRef.onSnapshot(
{ includeMetadataChanges: true },
snapshot => {
if (snapshot.exists) {
const data = snapshot.data();
const isFromCache = snapshot.metadata.fromCache;
const hasPendingWrites = snapshot.metadata.hasPendingWrites;
console.log('Data:', data);
console.log('From cache:', isFromCache);
console.log('Has pending writes:', hasPendingWrites);
// Update UI with offline indicators
updateUI(data, { offline: isFromCache, pending: hasPendingWrites });
}
},
error => {
console.error('Listener error:', error);
// Handle offline errors gracefully
if (error.code === 'unavailable') {
console.log('Service unavailable - using cached data');
}
}
);
};/**
* Cache size constant for unlimited cache
*/
const CACHE_SIZE_UNLIMITED: -1;
/**
* Settings interface for Firestore configuration
*/
interface Settings {
persistence?: boolean;
cacheSizeBytes?: number;
host?: string;
ssl?: boolean;
ignoreUndefinedProperties?: boolean;
serverTimestampBehavior?: 'estimate' | 'previous' | 'none';
}
/**
* Get options for specifying data source
*/
interface GetOptions {
source: 'default' | 'server' | 'cache';
}
/**
* Persistent cache index manager for query optimization
*/
interface PersistentCacheIndexManager {
enablePersistentCacheIndexAutoCreation(): Promise<void>;
disablePersistentCacheIndexAutoCreation(): Promise<void>;
deleteAllPersistentCacheIndexes(): Promise<void>;
}Install with Tessl CLI
npx tessl i tessl/npm-react-native-firebase--firestore