Read and Write Data on the Web Stay organized with collections Save and categorize content based on your preferences.
(Optional) Prototype and test withFirebase Local Emulator Suite
Before talking about how your app reads from and writes toRealtime Database,let's introduce a set of tools you can use to prototype and testRealtime Databasefunctionality:Firebase Local Emulator Suite. If you're trying out different datamodels, optimizing your security rules, or working to find the mostcost-effective way to interact with the back-end, being able to work locallywithout deploying live services can be a great idea.
ARealtime Database emulator is part of theLocal Emulator Suite, whichenables your app to interact with your emulated database content and config, aswell as optionally your emulated project resources (functions, other databases,and security rules).
Using theRealtime Database emulator involves just a few steps:
- Adding a line of code to your app's test config to connect to the emulator.
- From the root of your local project directory, running
firebase emulators:start. - Making calls from your app's prototype code using aRealtime Database platformSDK as usual, or using theRealtime Database REST API.
A detailedwalkthrough involvingRealtime Database andCloud Functions is available. You should also have a look at theLocal Emulator Suite introduction.
Get a database reference
To read or write data from the database, you need an instance offirebase.database.Reference:
Web
import{getDatabase}from"firebase/database";constdatabase=getDatabase();
Web
vardatabase=firebase.database();
Write data
This document covers the basics of retrieving data and how to order and filterFirebase data.
Firebase data is retrieved by attaching an asynchronous listener to afirebase.database.Reference. The listener is triggered once for theinitial state of the data and again anytime the data changes.
Basic write operations
For basic write operations, you can useset() to save data to a specifiedreference, replacing any existing data at that path. For example a socialblogging application might add a user withset() as follows:
Web
import{getDatabase,ref,set}from"firebase/database";functionwriteUserData(userId,name,email,imageUrl){constdb=getDatabase();set(ref(db,'users/'+userId),{username:name,email:email,profile_picture:imageUrl});}
Web
functionwriteUserData(userId,name,email,imageUrl){firebase.database().ref('users/'+userId).set({username:name,email:email,profile_picture:imageUrl});}
Usingset() overwrites data at the specified location, including any childnodes.
Read data
Listen for value events
To read data at a path and listen for changes, useonValue() to observeevents. You can use this event to read static snapshots of the contents at agiven path, as they existed at the time of the event. This methodis triggered once when the listener is attached and again every time the data, including children, changes. The event callback is passed a snapshot containingall data at that location, including child data. If there is no data, thesnapshot will returnfalse when you callexists() andnull when you callval() on it.
onValue() is called every time data is changed atthe specified database reference, including changes to children. To limit thesize of your snapshots, attach only at the lowest level needed for watchingchanges. For example, attaching a listener to the root of your database isnot recommended.The following example demonstrates a social blogging application retrieving thestar count of a post from the database:
Web
import{getDatabase,ref,onValue}from"firebase/database";constdb=getDatabase();conststarCountRef=ref(db,'posts/'+postId+'/starCount');onValue(starCountRef,(snapshot)=>{constdata=snapshot.val();updateStarCount(postElement,data);});
Web
varstarCountRef=firebase.database().ref('posts/'+postId+'/starCount');starCountRef.on('value',(snapshot)=>{constdata=snapshot.val();updateStarCount(postElement,data);});
The listener receives asnapshot that contains the data at the specifiedlocation in the database at the time of the event. You can retrieve the datain thesnapshot with theval() method.
Read data once
Read data once with get()
The SDK is designed to manage interactions with database servers whether yourapp is online or offline.
Generally, you should use the value event techniques described above to readdata to get notified of updates to the data from the backend. The listenertechniques reduce your usage and billing, and are optimized togive your users the best experience as they go online and offline.
If you need the data only once, you can useget() to get a snapshot of thedata from the database. If for any reasonget() is unable to return the servervalue, the client will probe the local storage cache and return an error if thevalue is still not found.
Unnecessary use ofget() can increase use of bandwidth and lead to loss ofperformance, which can be prevented by using a realtime listener as shown above.
Web
import{getDatabase,ref,child,get}from"firebase/database";constdbRef=ref(getDatabase());get(child(dbRef,`users/${userId}`)).then((snapshot)=>{if(snapshot.exists()){console.log(snapshot.val());}else{console.log("No data available");}}).catch((error)=>{console.error(error);});
Web
constdbRef=firebase.database().ref();dbRef.child("users").child(userId).get().then((snapshot)=>{if(snapshot.exists()){console.log(snapshot.val());}else{console.log("No data available");}}).catch((error)=>{console.error(error);});
Read data once with an observer
In some cases you may want the value from the local cache to be returnedimmediately, instead of checking for an updated value on the server. In thosecases you can useonce() to get the data from the local disk cache immediately.
This is useful for data that only needs to be loaded once and isn't expected tochange frequently or require active listening. For instance, the blogging appin the previous examples uses this method to load a user's profile when theybegin authoring a new post:
Web
import{getDatabase,ref,onValue}from"firebase/database";import{getAuth}from"firebase/auth";constdb=getDatabase();constauth=getAuth();constuserId=auth.currentUser.uid;returnonValue(ref(db,'/users/'+userId),(snapshot)=>{constusername=(snapshot.val() &&snapshot.val().username)||'Anonymous';// ...},{onlyOnce:true});
Web
varuserId=firebase.auth().currentUser.uid;returnfirebase.database().ref('/users/'+userId).once('value').then((snapshot)=>{varusername=(snapshot.val() &&snapshot.val().username)||'Anonymous';// ...});
Updating or deleting data
Update specific fields
To simultaneously write to specific children of a node without overwriting otherchild nodes, use theupdate() method.
When callingupdate(), you can update lower-level child values byspecifying a path for the key. If data is stored in multiple locations to scalebetter, you can update all instances of that data usingdata fan-out.
For example, a social blogging app might create a post and simultaneously updateit to the recent activity feed and the posting user's activity feed usingcode like this:
Web
import{getDatabase,ref,child,push,update}from"firebase/database";functionwriteNewPost(uid,username,picture,title,body){constdb=getDatabase();// A post entry.constpostData={author:username,uid:uid,body:body,title:title,starCount:0,authorPic:picture};// Get a key for a new Post.constnewPostKey=push(child(ref(db),'posts')).key;// Write the new post's data simultaneously in the posts list and the user's post list.constupdates={};updates['/posts/'+newPostKey]=postData;updates['/user-posts/'+uid+'/'+newPostKey]=postData;returnupdate(ref(db),updates);}
Web
functionwriteNewPost(uid,username,picture,title,body){// A post entry.varpostData={author:username,uid:uid,body:body,title:title,starCount:0,authorPic:picture};// Get a key for a new Post.varnewPostKey=firebase.database().ref().child('posts').push().key;// Write the new post's data simultaneously in the posts list and the user's post list.varupdates={};updates['/posts/'+newPostKey]=postData;updates['/user-posts/'+uid+'/'+newPostKey]=postData;returnfirebase.database().ref().update(updates);}
This example usespush() to create a post in the node containing posts forall users at/posts/$postid and simultaneously retrieve the key. The key canthen be used to create a second entry in the user'sposts at/user-posts/$userid/$postid.
Using these paths, you can perform simultaneous updates to multiple locations inthe JSON tree with a single call toupdate(), such as how this examplecreates the new post in both locations. Simultaneous updates made this wayare atomic: either all updates succeed or all updates fail.
Add a Completion Callback
If you want to know when your data has been committed, you can add acompletion callback. Bothset() andupdate() take an optional completioncallback that is called when the write has been committed to the database. Ifthe call was unsuccessful, the callback is passed anerror object indicating why the failure occurred.
Web
import{getDatabase,ref,set}from"firebase/database";constdb=getDatabase();set(ref(db,'users/'+userId),{username:name,email:email,profile_picture:imageUrl}).then(()=>{// Data saved successfully!}).catch((error)=>{// The write failed...});
Web
firebase.database().ref('users/'+userId).set({username:name,email:email,profile_picture:imageUrl},(error)=>{if(error){// The write failed...}else{// Data saved successfully!}});
Delete data
The simplest way to delete data is to callremove() on a reference to thelocation of that data.
You can also delete by specifyingnull as the value for another writeoperation such asset() orupdate(). You can use this techniquewithupdate() to delete multiple children in a single API call.
Receive aPromise
To know when your data is committed to theFirebase Realtime Database server, youcan use aPromise.Bothset() andupdate() can return aPromise you can use to know when thewrite is committed to the database.
Detach listeners
Callbacks are removed by calling theoff() method on yourFirebase database reference.
You can remove a single listener by passing it as a parameter tooff().Callingoff() on the location with no arguments removes all listeners at thatlocation.
Callingoff() on a parent listener does notautomatically remove listeners registered on its child nodes;off() must also be called on any child listenersto remove the callback.
Save data as transactions
When working with data that could be corrupted by concurrentmodifications, such as incremental counters, you can use atransaction operation.You can give this operation an update function and an optionalcompletion callback. The update function takes the current state of the data asan argument and returns the new desired state you would like to write. Ifanother client writes to the location before your new value is successfullywritten, your update function is called again with the new current value, andthe write is retried.
For instance, in the example social blogging app, you could allow users tostar and unstar posts and keep track of how many stars a post has receivedas follows:
Web
import{getDatabase,ref,runTransaction}from"firebase/database";functiontoggleStar(uid){constdb=getDatabase();constpostRef=ref(db,'/posts/foo-bar-123');runTransaction(postRef,(post)=>{if(post){if(post.stars &&post.stars[uid]){post.starCount--;post.stars[uid]=null;}else{post.starCount++;if(!post.stars){post.stars={};}post.stars[uid]=true;}}returnpost;});}
Web
functiontoggleStar(postRef,uid){postRef.transaction((post)=>{if(post){if(post.stars &&post.stars[uid]){post.starCount--;post.stars[uid]=null;}else{post.starCount++;if(!post.stars){post.stars={};}post.stars[uid]=true;}}returnpost;});}
Using a transaction prevents star counts from being incorrect if multipleusers star the same post at the same time or the client had stale data. If thetransaction is rejected, the server returnsthe current value to the client, which runs the transaction again with theupdated value. This repeats until the transaction is accepted or you abortthe transaction.
Note: Because your update function is called multiple times, it must be able tohandlenull data. Even if there is existing data in your remote database,it may not be locally cached when the transaction function is run, resultinginnull for the initial value.Atomic server-side increments
In the above use case we're writing two values to the database: the ID ofthe user who stars/unstars the post, and the incremented star count. If wealready know that user is starring the post, we can use an atomic incrementoperation instead of a transaction.
Web
functionaddStar(uid,key){import{getDatabase,increment,ref,update}from"firebase/database";constdbRef=ref(getDatabase());constupdates={};updates[`posts/${key}/stars/${uid}`]=true;updates[`posts/${key}/starCount`]=increment(1);updates[`user-posts/${key}/stars/${uid}`]=true;updates[`user-posts/${key}/starCount`]=increment(1);update(dbRef,updates);}
Web
functionaddStar(uid,key){constupdates={};updates[`posts/${key}/stars/${uid}`]=true;updates[`posts/${key}/starCount`]=firebase.database.ServerValue.increment(1);updates[`user-posts/${key}/stars/${uid}`]=true;updates[`user-posts/${key}/starCount`]=firebase.database.ServerValue.increment(1);firebase.database().ref().update(updates);}
This code does not use a transaction operation, so it does not automatically getre-run if there is a conflicting update. However, since the increment operationhappens directly on the database server, there is no chance of a conflict.
If you want to detect and reject application-specific conflicts, such as a userstarring a post that they already starred before, you should write customsecurity rules for that use case.
Work with data offline
If a client loses its network connection, your app will continue functioningcorrectly.
Every client connected to a Firebase database maintains its own internal versionof any active data. When data is written, it's written to this local versionfirst. The Firebase client then synchronizes that data with the remote databaseservers and with other clients on a "best-effort" basis.
As a result, all writes to the database trigger local events immediately, beforeany data is written to the server. This means your app remainsresponsive regardless of network latency or connectivity.
Once connectivity is reestablished, your app receives the appropriate set ofevents so that the client syncs with the current server state, without having towrite any custom code.
Note: TheFirebase Realtime Database web APIs do not persist data offline outsideof the session. In order for writes to be persisted to the server, the webpage must not be closed before the data is written to the serverWe'll talk more about offline behavior inLearn more about online and offline capabilities..
Next steps
- Working with lists of data
- Learn how to structure data
- Learn more about online and offline capabilities
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 2025-12-17 UTC.