Skip to content
All posts
June 11, 20264 min read

Firebase Realtime DB vs Firestore: Why Stream Semantics Won for Family Location Tracking

Choosing a Firebase database for real-time location sharing is not a preference decision — it's a constraint decision. Here is why Firebase Realtime DB won over Firestore for MyFamilyTracker, and what the tradeoff actually costs.

AndroidFirebaseArchitecture
Share:

The common advice is to use Firestore. It scales better. It has richer querying. It supports subcollections. The documentation is better. Most new Firebase projects should start with Firestore.

MyFamilyTracker did not start with Firestore. Here is why.


The constraint: a location feed is a stream, not a document

Family location tracking has one hard requirement: when a family member moves, every other connected device should see it as soon as possible.

Firestore delivers updates via document snapshots. When you attach a listener to a document, Firestore sends you the full document every time it changes. For a location that updates every few seconds, this works fine.

The problem is the polling semantics underneath. Firestore's real-time updates are push-based at the SDK level, but the underlying model is still document-oriented. If a location document hasn't changed, there is nothing to push. If you want to distinguish "location unchanged" from "device disconnected," Firestore doesn't give you a clean primitive for that.

Firebase Realtime DB was designed around stream semantics from the start. When you write a value, it propagates to all connected listeners in under a second. The connection itself is stateful — the SDK maintains a persistent WebSocket connection, and you can observe connection state directly.

For a location feed, this matters:

kotlin
// Firebase Realtime DB — persistent connection, stream semantics
val ref = database.getReference("locations/$userId")
ref.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        // fires immediately on any change, sub-second propagation
        updateMapMarker(snapshot.getValue(LocationData::class.java))
    }
    override fun onCancelled(error: DatabaseError) { }
})

// Also: observe connection state
val connectedRef = database.getReference(".info/connected")
connectedRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        val connected = snapshot.getValue(Boolean::class.java) ?: false
        updateConnectionState(connected)
    }
    override fun onCancelled(error: DatabaseError) { }
})

Firestore has

code
addSnapshotListener
which is also real-time, but the connection state primitive (
code
.info/connected
) doesn't exist. Detecting disconnection in Firestore requires inference from update timestamps, which is a derived signal rather than a first-class one.


What Realtime DB costs

The tradeoff is real. Firebase Realtime DB has meaningful limitations compared to Firestore:

No compound queries. Firestore lets you filter on multiple fields simultaneously. Realtime DB requires you to index and denormalize your data to support any query you want to run. For MyFamilyTracker, this means the data structure is flat — one node per user, no complex query needs — so this constraint costs nothing. For an app with complex querying requirements, it would be the wrong choice.

No subcollections. Realtime DB is a JSON tree. Deep nesting means reading a node reads all its children. This forces careful data structure design. Again, for location sharing, the structure is simple enough that this isn't a constraint.

Weaker security rules. Firestore security rules are more expressive. Realtime DB rules work, but they are less powerful for complex authorization patterns. For MyFamilyTracker's use case (family members can see each other's locations within a group), the rules are straightforward.

Scale ceiling. Firebase Realtime DB doesn't scale as gracefully as Firestore at very high write volume. For a family of 2–10 people updating location every few seconds, this is nowhere near a concern.


The data structure decision

Because Realtime DB punishes deep nesting, the location data is kept flat:

code
/locations
  /{userId}
    /lat: 13.7563
    /lng: 100.5018
    /accuracy: 12.5
    /timestamp: 1715145600000
    /isSharing: true

/groups
  /{groupId}
    /members
      /{userId}: true
    /name: "Family"
    /ownerId: "{userId}"

Each user has exactly one location node. Groups store member IDs as boolean keys (the Realtime DB pattern for set membership). Querying all members in a group and then fetching their locations is two reads, not one compound query — and that's fine for this use case.

Firestore would let you do this in a single compound query. But for a family of 2–10 members, two reads costs microseconds and adds zero complexity. The simplicity of the flat structure is worth more than the elegance of the single query.


The offline behavior difference

Both Firebase Realtime DB and Firestore support offline persistence. The behavior differs.

Firestore's offline cache is document-based. It caches the last known state of documents you've accessed and serves them from cache when offline.

Realtime DB's offline persistence works similarly but with one useful addition: the

code
keepSynced
call tells the SDK to maintain a local copy of a node even when the app isn't actively listening:

kotlin
database.getReference("locations").keepSynced(true)

This means the last known location of every family member is always available offline, regardless of whether the UI is actively showing it. For a location-sharing app where a family member might check a location while temporarily offline (on a subway, in a building with poor signal), this is useful behavior.


What would make Firestore the right choice

If MyFamilyTracker were to add:

  • Location history queries (show where someone was between time A and time B)
  • Filtering by location accuracy or recency across multiple users
  • Complex group permission structures

...Firestore would become the better choice. The querying flexibility would be worth the loss of the

code
.info/connected
primitive and the slightly higher latency on simple stream updates.

For the current feature set — real-time location sharing, geofencing, offline cache, connection state — Firebase Realtime DB is the better fit. The constraint drove the choice, not the preference.

Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus

Apps tagged with this