Chapter 08 · Offline Persistence, Local Cache, Synchronization, Conflict Behavior, and Offline Indexes

Memory vs Persistent Cache Options, Multi-Tab / Process Considerations, and Sensitive-Data Risk

Choose Firestore memory versus persistent cache, Web single/multi-tab behavior, sign-out/clearing policy and sensitive-data controls.

Intermediate115–140 minutesCache privacy + lifecycleFirebase JS 12.19.0 · CLI 15.30.0Last reviewed: September 2026

Learning outcomes

01

Choose memory or persistent cache from privacy, restart and offline requirements rather than platform folklore.

02

Configure Web single-tab versus multi-tab persistence and explain which state is coordinated across tabs.

03

Explain why sign-out is not equivalent to clearing Firestore cached data and design a test/reset or shared-device policy.

04

Distinguish browser-tab coordination from mobile multi-process assumptions and keep one explicit owner for Firestore lifecycle.

Execution and safety note

Use the Emulator Suite, a Firebase demo project, or an isolated test project for destructive, security-sensitive, billing-sensitive, migration, backup/restore, or write-heavy exercises unless the lesson explicitly marks managed verification as required. Treat shown output as expected evidence unless it is explicitly identified as captured output, and re-check current Firebase/Google Cloud edition, mode, quota, pricing, and security documentation before production execution.

Chapter 08 reproducibility baseline · reviewed 16 September 2026

AtlasMart continues the same environment used in Chapters 01–07: project ID demo-atlasmart-firestore, Standard edition / Native mode / (default) database for the mandatory lab, Firestore emulator 127.0.0.1:8080, Authentication emulator 127.0.0.1:9099, Emulator UI 127.0.0.1:4000, Firebase CLI 15.30.0, Firebase JavaScript SDK 12.19.0, Firebase Admin Node SDK 14.4.0 (bundling @google-cloud/firestore 9.1.0), and Node.js 22+. The emulator has no production location or billing contract; any production region, pricing, SLA, IAM and managed-service latency remain explicitly unproven by this lab.

Evidence boundary

The mandatory exercises run locally and deliberately manipulate client network state. They prove client-cache, queued-write, listener, Rules and synchronization behavior for the pinned SDK/emulator combination. They do not prove production WAN p95/p99 latency, device-OS background behavior, billing, data-recovery guarantees, real multi-region propagation, every browser storage policy, or Enterprise Pipeline behavior. Pipeline operations do not support offline persistence; Enterprise offline exercises must use Core operations.

1. AtlasMart problem: a shared kiosk remembers the previous shopper

A shopper signs out of AtlasMart on a family laptop. Authentication state is cleared, but a persistent Firestore cache can still hold documents from the previous session. Security Rules protect backend requests; they do not retroactively encrypt or securely erase bytes already stored in the browser profile. The cache mode is therefore part of the privacy architecture.

Choice Benefit Risk / operational cost
memory cache ephemeral process-lifetime state; simplest shared-device story reload/restart loses cache; weaker offline restart UX
persistent single-tab survives restart and supports offline continuity one persistence owner; stale/sensitive data persists
persistent multi-tab tabs/windows coordinate queries and mutations through shared persistence more lifecycle complexity; all tabs share the local data surface
unlimited/large cache more data remains available offline larger privacy/storage footprint and longer local scans without indexes

2. Web: choose persistence only after a trust decision

trusted-device cache selection
import { initializeApp } from "https://www.gstatic.com/firebasejs/12.19.0/firebase-app.js";import {  initializeFirestore, memoryLocalCache, persistentLocalCache,  persistentSingleTabManager, persistentMultipleTabManager,  connectFirestoreEmulator} from "https://www.gstatic.com/firebasejs/12.19.0/firebase-firestore.js";const app=initializeApp({projectId:"demo-atlasmart-firestore",apiKey:"demo-key",appId:"demo-app"});const trustedDevice = localStorage.getItem("atlasmart-trusted-device") === "yes";const multiTab = new URL(location.href).searchParams.get("tabs") === "multi";const localCache = trustedDevice  ? persistentLocalCache({      cacheSizeBytes: 40 * 1024 * 1024,      tabManager: multiTab ? persistentMultipleTabManager() : persistentSingleTabManager({})    })  : memoryLocalCache();const db=initializeFirestore(app,{localCache});connectFirestoreEmulator(db,"127.0.0.1",8080);

The Web SDK’s current persistentLocalCache() uses IndexedDB and accepts a cache-size threshold plus a tab manager. The threshold is a garbage-collection target, not a hard storage cap. The default persistent-cache threshold is 40 MB; do not turn off garbage collection casually. For Chrome/Safari/Firefox support, still test the actual deployment browser and storage policy.

3. Android and Apple defaults do not remove the privacy decision

ephemeral mobile cache intent
// Android: persistent disk cache is default; choose memory only when required.val settings = firestoreSettings {  setLocalCacheSettings(memoryCacheSettings { }) // privacy-sensitive/shared-device mode}Firebase.firestore.firestoreSettings = settings// Apple: persistent cache is default; choose memory explicitly for ephemeral mode.let settings = FirestoreSettings()settings.cacheSettings = MemoryCacheSettings()let db = Firestore.firestore()db.settings = settings

Android and Apple persistent cache is enabled by default, so a security review must explicitly decide whether that is acceptable for the application’s data classification. Device sandboxing is useful but does not make every cached field appropriate for persistence. Avoid caching secrets, privileged server-only fields, or data that should never exist on an untrusted client in the first place.

4. Multi-tab is a Web feature; do not invent multi-process guarantees

persistentMultipleTabManager() coordinates Firestore activity among browser tabs/windows using the same origin. It does not imply that arbitrary Android/iOS processes, WebViews, extensions or separate browser profiles share one coherent cache. Treat each application process/profile as a distinct client unless the platform SDK explicitly documents otherwise, and avoid multiple competing Firestore owners in a mobile multi-process architecture.

Lifecycle rule

Every listener, pending-write indicator, Auth user and cache policy belongs to a user/session/application lifecycle. “The SDK caches it” is not a lifecycle specification.

5. Sign-out is not cache clearing

Firebase Authentication sign-out changes authentication state. It does not promise to erase Firestore’s persistent cache. For test isolation, the Web SDK exposes clearIndexedDbPersistence(), but it must be called when Firestore is not running and it is explicitly not a secure-overwrite mechanism.

test reset: terminate + clear
import { terminate, clearIndexedDbPersistence } from "https://www.gstatic.com/firebasejs/12.19.0/firebase-firestore.js";// Test/reset workflow: stop listeners first, then terminate the Firestore instance.await terminate(db);await clearIndexedDbPersistence(db);// Create a fresh Firebase/Firestore instance before using Firestore again.// clearIndexedDbPersistence is test-oriented and is NOT a secure erase primitive.

For sensitive cross-session disclosure, the official guidance is stronger: consider not enabling persistent cache at all. A product requirement such as “no previous user data remains recoverable after sign-out” should not be implemented by assuming a test cleanup API is secure deletion.

6. Reproducible trust-device matrix

firebase.json
{  "firestore": { "rules": "firestore.rules", "indexes": "firestore.indexes.json", "edition": "standard" },  "emulators": {    "firestore": { "port": 8080, "edition": "standard" },    "auth": { "port": 9099 },    "ui": { "enabled": true, "port": 4000 }  }}
firestore.rules
rules_version = '2';service cloud.firestore {  match /databases/{database}/documents {    match /profiles/{uid} {      allow read, create, update: if request.auth != null && request.auth.uid == uid;      allow delete: if false;    }    match /carts/{uid} {      allow read, create, update: if request.auth != null && request.auth.uid == uid;      allow delete: if false;      match /items/{productId} {        allow read, create, update, delete: if request.auth != null && request.auth.uid == uid;      }    }    match /catalogItems/{productId} {      allow read: if true;      allow write: if false;    }    match /{document=**} { allow read, write: if false; }  }}
local setup
mkdir atlasmart-offline && cd atlasmart-offlinenpm init -ynpm install firebase-admin@14.4.0# Save firebase.json and firestore.rules from this lesson.printf '{"indexes":[],"fieldOverrides":[]}' > firestore.indexes.json# terminal Anpx firebase-tools@15.30.0 emulators:start --project demo-atlasmart-firestore --only firestore,auth# terminal B: serve browser filespython -m http.server 4173# then open http://127.0.0.1:4173/ in a supported browser
Run Cache Tabs After reload After sign-out
A memory single expect cache to be rebuilt Auth clears; no persistent Firestore cache from prior page process
B persistent single cached documents remain available Auth clears but Firestore cache can remain
C persistent multi two tabs can coordinate local persistence both tabs participate in the same local data surface

Use only synthetic profile/cart data. Record what survives reload and what survives sign-out. Then terminate/clear between test cases so a stale cache does not masquerade as emulator data after the emulator has been reset.

7. Wrong approach: “Rules deny the next read, so cached data is gone”

Rules govern backend access. An already-cached document may still be present on the device and can participate in local query/listener behavior until local state changes or is cleared. This is why data minimization and cache-mode selection matter even when Rules are correct.

Production judgment

Classify client-visible data, decide whether persistent cache is allowed per device type, publish a user-visible “trusted device” policy when appropriate, and test shared-device logout. Add telemetry for persistence initialization failures/fallbacks without logging document contents. Lesson 4 turns to performance: persistent caches can need local query indexes as they grow.

Knowledge check

  1. Does Firebase Auth sign-out securely erase Firestore cache?
  2. What is Web multi-tab persistence for?
  3. Is the persistent Web cache-size setting a hard cap?
  4. When should a privacy-sensitive app prefer memory cache?
  5. Is clearIndexedDbPersistence() a secure erase primitive?
Review the answers

1. No. Authentication state and Firestore local persistence are separate lifecycles.

2. It coordinates persistent Firestore cache/query/mutation activity among tabs/windows sharing the same origin.

3. No. It is an approximate garbage-collection threshold.

4. When persistent local disclosure across sessions/devices is not acceptable or not needed.

5. No. It is primarily a test/reset utility and does not securely overwrite cached data.

Summary and next step

Cache configuration is a privacy and lifecycle decision. Lesson 4 shows how persistent local query indexes change offline query performance without changing server indexes.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.