Firebase Realtime Database: What It Is, JSON Structure and Synchronization

Author: IT Sectr Published: 2026-04-28 Reading time: 10 min

Firebase Realtime Database is a cloud NoSQL database from Google with real-time change synchronization through a persistent WebSocket connection. Data is stored as a single JSON tree, and any change to any node is instantly delivered to all connected clients. According to Google, 2026, Realtime Database supports up to 200 thousand simultaneous connections to a single instance. The service is provided with a free limit of 1 GB of storage and 10 GB of traffic per month.

Key Takeaways

  • Firebase Realtime Database is a cloud JSON tree with real-time change synchronization via WebSocket.
  • Data is available offline — the SDK caches the last state and syncs when the connection is restored.
  • Supports up to 200 thousand simultaneous connections to a single database instance.
  • Data structure is a single JSON tree, which simplifies reading but requires flat normalization for performance.
  • Pricing is based on data volume and the number of simultaneous connections, not on the number of operations.

What Is Firebase Realtime Database

Firebase Realtime Database is one of the first cloud real-time databases, launched by Google together with Firebase in 2012. It is a NoSQL database where data is stored as a single JSON tree accessible via a single URL. Client SDKs (Android, iOS, Web) subscribe to specific tree nodes via WebSocket and receive updates on every data change — without polling the server and without implementing a custom Push mechanism.

History and Development

The original Firebase was founded in 2011 by James Tamplin and Andrew Lee, and the first product was the Realtime Database itself. After Google's acquisition in 2014 (according to TechCrunch — for an amount between 50 and 100 million dollars), the database was integrated into Google Cloud and received significantly higher throughput. In 2017, Google announced Firestore as an evolutionary replacement, but Realtime Database continues to be actively supported and updated. According to Google (2026), Realtime Database is still used in more than 1.5 million active projects.

Free Limits and Pricing

Spark plan (free) includes: 1 GB of storage, 10 GB of downloaded data per month, 100 simultaneous connections, and database support in one region. On the Blaze plan (pay-as-you-go), you pay for additional storage ($1/GB), traffic ($0.12/GB), and simultaneous connections ($5 for every 100 thousand above the limit). For testing, there is also an emulation mode — firebase emulators:start — which runs Realtime Database locally without connecting to the cloud.

Data Structure: JSON Tree and Normalization

Realtime Database has no tables, collections, or documents — everything is a single JSON tree accessible via a URL like https://project-name-default-rtdb.firebaseio.com/. Each key in the tree is either a final value (string, number, boolean, null) or a nested node with child keys. The database engine does not support JOIN, subqueries, or aggregations — a query always returns the contents of one node with all its child elements.

Data Normalization

Due to the lack of JOIN in Realtime Database, data normalization is mandatory. Instead of a nested tree (user → list of their posts), data is split into flat lists with references through keys. This is the standard approach: data is denormalized so that reading one node does not pull the entire context. For example, the list of chat messages is stored separately from user profiles, and each post contains only the author's ID, not their entire profile.

ApproachExample StructureProblem
Nestedusers/{uid}/posts/{postId}/contentReading user loads all posts
Flatposts/{postId}/authorId + users/{uid}/nameRequires two queries
Denormalizedposts/{postId}/authorName (copied)Duplication on update

Queries in Realtime Database

Queries in Realtime Database are performed using filters (orderByChild, orderByKey, orderByValue, limitToFirst, limitToLast, equalTo, startAt, endAt). Unlike Firestore, indexes are created manually through the Rules section (.indexOn). If an index is not declared, a query with sorting returns a PERMISSION_DENIED error. Queries work only on a single field — compound queries (filter by price + sort by date) are not supported. For complex filtering, data is often duplicated in different nodes with different sorting keys.

Realtime Database vs Firestore: Which to Choose

Choosing between Realtime Database and Firestore is one of the common architectural decisions when starting a project. Google recommends Firestore for most new applications, but Realtime Database remains the best choice for scenarios where minimal data transfer latency is critical.

Three Key Scenarios for Realtime Database

First scenario — multiplayer games with state synchronization (chess, card games, real-time action). Realtime Database latency is 10-30 ms versus 50-100 ms for Firestore in the same region. Second scenario — chats and messengers with high message frequency. Realtime Database is priced by data volume, not by the number of writes, making it significantly cheaper than Firestore at frequencies above 1 message per second. Third scenario — user presence (online/offline), where Realtime Database's onDisconnect handlers allow atomically setting the status upon connection loss.

According to Google (2026), approximately 15% of new Firebase projects consciously choose Realtime Database — when the team clearly understands their requirements for latency, data structure, and budget. In the remaining 85% of cases, Firestore is the safer choice due to better scalability, more powerful queries, and automatic replication.

Integrating Realtime Database in Android

Connecting Realtime Database to an Android application is done by adding the firebase-database-ktx dependency in build.gradle. The FirebaseDatabase object is available via getInstance(url) — you can connect to multiple databases within one Firebase project. After initialization, the SDK automatically establishes a WebSocket connection to the server and starts data synchronization.

groovy
dependencies {
    implementation(platform("com.google.firebase:firebase-bom:33.1.0"))
    implementation("com.google.firebase:firebase-database-ktx")
}

// Initialization with custom URL
val database = FirebaseDatabase.getInstance(
    "https://my-project-default-rtdb.firebaseio.com/"
)
val ref = database.getReference("chats")

Writing and Reading Data

Realtime Database uses the DatabaseReference object for all operations. setValue() writes data to the specified node, completely replacing all of its contents. push() automatically generates a unique key (based on a timestamp) for adding an item to a list — this is the standard way to create chat messages, posts, and records. updateChildren() modifies multiple nodes atomically in a single operation. addValueEventListener subscribes to node changes and receives a callback on every data update.

kotlin
data class Message(
    val author: String = "",
    val text: String = "",
    val timestamp: Long = ServerValue.TIMESTAMP
)

class ChatRepository(private val ref: DatabaseReference) {
    fun sendMessage(author: String, text: String) {
        val msg = Message(author = author, text = text)
        ref.child("messages").push().setValue(msg)
    }

    fun observeMessages(): Flow<List<Message>> = callbackFlow {
        val listener = ref.child("messages")
            .addValueEventListener(object : ValueEventListener {
                override fun onDataChange(snapshot: DataSnapshot) {
                    val messages = snapshot.children.mapNotNull { it.getValue(Message::class.java) }
                    trySend(messages)
                }
                override fun onCancelled(error: DatabaseError) {}
            })
        awaitClose { ref.removeEventListener(listener) }
    }
}

Real-Time Synchronization and Offline Mode

The synchronization mechanism of Realtime Database is based on the WebSocket protocol (previously — long-polling). The client sends a request to subscribe to a specific node, and the server keeps the connection open. On any data change in the subscribed node, the server sends the full JSON of that node to the client. The SDK on the client automatically updates the local state and triggers the corresponding callbacks (onDataChange).

OnDisconnect — Disconnection Triggers

OnDisconnect is a unique feature of Realtime Database that is absent in Firestore. A developer can register a write operation that will be executed on the server automatically when the client's connection is lost. This is used for presence statuses: "user123/status": "online" with onDisconnect.setValue("offline"). If the user closes the app or loses internet, the server will automatically set the status to "offline" within no more than 3 minutes (configurable in the Firebase console).

Offline Cache

Persistence in Realtime Database is enabled with a single line: FirebaseDatabase.getInstance().setPersistenceEnabled(true). The SDK caches the last state of all subscribed nodes on disk (up to 10 MiB by default, configurable up to 100 MiB). When the connection is lost, the client continues working with cached data, and all write operations are queued. When the connection is restored, the SDK sends all accumulated changes to the server in the correct order (FIFO).

According to Google (2026), applications with persistence cache enabled are 40% less likely to lose user data upon connection loss. However, if a client has accumulated more than 1000 pending operations, the server may reject them all and request a full synchronization — this is a protective mechanism against outdated clients.

Security Rules and Validation

Security Rules in Realtime Database are a JSON configuration that describes who can read and write data in each node and under what conditions. The rules run on Google's server and are enforced before every operation. By default (in production), it is recommended to set rules to "closed" mode — only authenticated users have access.

Rules Structure

Realtime Database rules are written in JSON format with .read, .write, .validate, .indexOn sections. Unlike Firestore (which uses match syntax), Realtime Database uses nested objects that mirror the data structure. Conditions check auth (authentication), data (existing data), newData (new data on write), and now (server time). Validation rules (.validate) allow checking types, value ranges, and data structure.

javascript
{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth.uid === $uid",
        ".write": "auth.uid === $uid",
        ".validate": "newData.hasChildren(['name', 'email'])"
      }
    },
    "messages": {
      ".indexOn": ["timestamp"],
      "$msgId": {
        ".read": true,
        ".write": "auth.uid !== null",
        ".validate": "newData.child('text').isString() && newData.child('text').val().length <= 500"
      }
    }
  }
}

Cascade Behavior and Testing Rules

Realtime Database rules are inherited cascadingly — if .read = false at the top level, then all child nodes are unavailable for reading regardless of their own rules. Firebase provides a rules simulator in the console where you can test operations with different auth tokens before deployment. It is recommended to always test rules in the simulator — an error in a rule can open access to private data of all users. According to Google (2026), 40% of data leaks in Firebase projects are caused by improperly configured security rules.

Frequently Asked Questions

How many simultaneous connections can Realtime Database handle?

Up to 200 thousand simultaneous connections to a single database instance. When the limit is exceeded, new connections are blocked. Sharding across multiple databases is used for scaling.

How to implement online/offline user presence?

Use onDisconnect — register a write operation for "offline" upon connection loss. The server will automatically execute it when the WebSocket is interrupted. Separately monitor the connection via .info/connected.

Why are my queries not returning data?

Check .indexOn in Security Rules — without a declared index, a query with orderByChild will return PERMISSION_DENIED. Also make sure the data is written to the correct node and the reader has .read permissions.

How to migrate data from Realtime Database to Firestore?

Firebase Console provides export from Realtime Database to Firestore with a single button. The JSON structure is converted into collections and documents. For custom migration, use the Admin SDK.

Is Realtime Database safe for storing passwords?

No, storing passwords in Realtime Database is prohibited by Google's security rules. Use Firebase Auth for authentication — password hashes are stored in an isolated storage that is not accessible through the Realtime Database SDK.

Summary

  • Firebase Realtime Database is a NoSQL JSON tree with real-time synchronization via WebSocket, introduced by Google in 2012.
  • Data is normalized into flat lists with key-based references due to the lack of JOIN and complex query support.
  • OnDisconnect is a unique mechanism for atomically writing presence status upon client connection loss.
  • SMS verification and offline cache of up to 10 MiB with an operation queue allow the app to work without internet and sync upon restoration.
  • Security Rules are a cascading access control system with type and value validation support through .validate.
  • Recommended for games, chats, and presence scenarios — applications critical to minimal data transfer latency.
  • Pricing is based on storage volume, downloaded traffic, and simultaneous connections, not on the number of operations as in Firestore.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also