If you're building an application with React or React Native and want to add login, a real-time database, or simply stop worrying about the backend, Firebase is one of the most convenient and powerful options you have right now.It allows you to have authentication, database, file storage and much more without setting up a single API of your own.
In this article we will see, step by step, How to connect a React app (and also React Native / Expo) with FirebaseWe'll cover how to structure your project, configure email and Google authentication, persist user sessions, and read/write data to both Firestore and the Realtime Database. We'll use real-world examples and commented code, explaining everything in simple terms so you can follow along even if you're not a tech expert.
What is Firebase and why does it fit so well with React?
Firebase is a Google Backend as a Service It offers a range of ready-to-use services: authentication, real-time database, Firestore (a NoSQL document database), file storage, analytics, growth tools, monetization, and more. It started as a real-time database, but after several iterations, it has become a very complete backend platform.
Instead of setting up your own server, designing your API, managing the infrastructure and scaling it, with Firebase you can Connect your React app directly to the backend using its official SDKThis means that many typical backend tasks (auth, CRUD, security rules, notifications, etc.) are reduced to a few calls to well-documented JavaScript functions.
Integrating with React is very natural because Firebase exposes its data in JSON format. And their SDKs are designed to work on the client side. With React, you simply read that data, put it into the state of your components, and let the library handle rendering everything whenever something changes. When you use their real-time listeners, every database update triggers an automatic re-render, which fits perfectly with React's declarative model.
Create and configure a Firebase project
Before you start writing React code, you need to have your Firebase environment ready. The process is very similar whether you're using it from a React web app, React Native, or Expo. In all cases, The first step is to create the project in the Firebase console.
Sign in https://firebase.google.com/Sign in with your Google account and access the console. From there, create a new projectGive it a recognizable name (for example, “react-firebase” or “auth-firebase-react”) and select the region that makes the most sense for your application's audience.
Once the project is created, Firebase will take you to the main dashboard. You'll see several options for adding apps: iOS, Android, and Web. For a React web app, you select the web icon, while for React Native you can register iOS and/or Android apps as needed. The goal in all cases is to obtain a Firebase configuration with keys such as apiKey, authDomain, projectId and similar.
The console will show you a code snippet that looks something like this:
const config = { apiKey: "AIzaSy*", authDomain: "tu-proyecto.firebaseapp.com", databaseURL: "https://tu-proyecto.firebaseio.com", projectId: "tu-proyecto", storageBucket: "tu-proyecto.appspot.com", messagingSenderId: "796"};firebase.initializeApp(config);
In React web you really only need the configuration object and the call to initializeApp**using the current modular SDK. You'll see how to fit this into your project structure later.
Choosing a database: Realtime Database vs Firestore
Firebase offers you two main types of databases: the Realtime Database y Cloud FirestoreBoth are NoSQL, but they have important differences in data model, queries, and billing methods.
A Realtime Database is a giant JSON database where everything is organized into a single tree structure. It's ideal when you need Very fast updates and easy real-time synchronizationThe structure is based on nodes and paths, and you access them with references such as firebase.database().ref('object/name')It's the classic option if you want something like chat, user presence, or very simple data.
Firestore, for its part, organizes the information into collections and documentsEach document has fields, and you can nest subcollections within them. It allows for more complex queries, composite indexes, sorting, and combined filters. It's perfect for slightly larger applications where you need... flexible queries, scalability, and more expressive security rules.
Both databases can be used seamlessly from React, even within the same app. For example, you can store users, posts, or tasks in Firestore and leverage the Realtime Database for highly dynamic data that you want to monitor continuously. The important thing to understand is that in React, you only need to... Listen for changes and update the statusFirebase does the rest for you.
Create a React Native / Expo app with Firebase

If you work with React Native, you can integrate Firebase using the Firebase Web SDKwhich is fully compatible with projects created with Expo or the official React Native CLI. This way you're not tied to intermediate libraries and you stay within what Google officially supports.
To get started with Expo, install the Expo CLI globally from the terminal using npm install -g expo-cliNext, create a new React Native project with expo initChoose a basic template (for example, "blank" with managed workflow) and start the app with yarn ios o yarn androidExpo will show you a QR code that you can scan with the camera on iOS or with the Expo app on Android to view your project on the device.
Once you have your base app running, add the necessary dependencies: first, the Firebase SDK itself, with yarn add firebaseThen you can incorporate navigation libraries such as @react-navigation/native y @react-navigation/stack, along with the additional packages they need in React Native (gesture-handler, reanimated, screens, safe-area-context, etc.) to manage the flows between login, registration and home screens.
It is also very useful to install some auxiliary components for the mobile UI, for example react-native-keyboard-aware-scroll-view to properly manage the keyboard in forms, and libraries like base-64 To provide global functions missing in some mobile runtimes (btoa, atob, etc.). All of this is added with a single installation command using yarn in your project.
Set up Firebase in React / React Native
You'll centralize your Firebase configuration in a single file, so the rest of the application only needs to import a pre-initialized instance. Create, for example, a folder src/firebase and inside a configuration file, like config.js (o config.ts in TypeScript).
In that file, import the necessary functions from the Firebase SDK and define your configuration object with the values provided by the Firebase console. In React Native projects using the older SDK, you might see something like this:
import * as firebase from 'firebase';import '@firebase/auth';import '@firebase/firestore';const configuracionFirebase = { apiKey: 'TU_CLAVE_API', authDomain: 'tu-dominio-auth.firebaseapp.com', databaseURL: 'https://tu-bd.firebaseio.com', projectId: 'tu-id-proyecto', storageBucket: 'tu-id-proyecto.appspot.com', messagingSenderId: '1234567890', appId: '1:1234567890:web:codigoapp'};if (!firebase.apps.length) { firebase.initializeApp(configuracionFirebase);}export { firebase };
Web projects using Vite and TypeScript typically use the modular version of the Firebase SDK 9, and it's good practice to place sensitive values in environment variablesFor example, you can create a file .env in the root and define keys as VITE_FIREBASE_API_KEY, VITE_FIREBASE_AUTH_DOMAINetc. Then, in the configuration file, you construct the object from import.meta.env['VITE_FIREBASE_API_KEY'] and the like.
Regardless of the approach, the pattern is the same: you initialize the Firebase app only once and export that instance (or you export specific objects like FirebaseAuth, Firestore o Realtime Database) to easily use it in the rest of the project.
Basic screen architecture: login, registration and home
When you integrate authentication into a React Native app, a very common structure is to have three main screens: Login, Register y HomeAdditionally, you can centralize the navigation logic in a single root component, typically App.js.
In React Native with React Navigation, the typical thing to do is to create a folder src/screens with subfolders per screen (LoginScreen, RegistrationScreen, HomeScreen) and an index file that exports each of them. Then, in app.jsYou create a stack navigator that displays one screen or another depending on whether there is an authenticated user or not.
The idea is to save the component's state. App un user (or null) and a flag of loadingWhile the authentication status is being checked, you can display a blank screen or a loader. Once you know if the user is logged in, you decide which routes to show: if there is a user, show the home screen; if not, show the login and registration screens.
Visually, the login and registration screens are simple forms with fields such as email, password, and, in the case of registration, full name or password confirmation. To improve the mobile experience, everything is usually wrapped with a KeyboardAwareScrollView so that the keyboard doesn't cover the inputs. The Home screen, meanwhile, can start as a minimal view (simple text) and later evolve into the part of the app where you read and write data from Firestore.
Designing and managing forms with hooks in React
In a React web application with TypeScript, a clean way to handle authentication forms is to encapsulate the logic in a custom hookFor example, you can create useForm.tsx in a folder src/hooks, that receives a generic initial state (an object with the form's properties) and returns both the values and a function to handle the changes.
That hook can use useState internally to store the form and expose a function handleChange that receives the input event, reads the attribute name of the element and update the corresponding property in the state. This way, you'll have the correct names in the inputs (for example, name="email" y name="pass") is key to making everything work.
In the login component, for example, you would call useForm({ email: '', pass: '' }) And you would get the email, the password, the form object, and the handleChange function. Each input would have its own value y onChange linked to those values and the hook's function. When submitting the form, you would have a handleSubmit what does e.preventDefault() and then calls the authentication logic with Firebase.
The same applies to the registration form; you could even extract a reusable form component, since often only the button text and the callback executed on submit change, while the basic structure remains the same.
Configure authentication in Firebase
For React to authenticate against Firebase, you need to enable the authentication providers in the Firebase console. From the section of Authentication, go to the access methods tab (Sign-in method) and activates the email address / password And, if you're interested, the supplier of Google.
For the email/password provider, simply enable it and save. For Google, in addition to enabling it, you'll need to select the email address that will be used by default. From then on, your project will be ready to accept logins using both methods.
In the users tab (UsersIn the same section, you'll see how new accounts created from your application are registered, either with email and password or via Google. It's a good place to verify that the field-to-field integration is working correctly.
Authentication features with Firebase in React
In a web app using React and TypeScript, it's recommended to group all the authentication logic in a services file, for example. src/firebase/services.tsThere you can have specific functions for each action: login with Google, login with credentials, registration, logout, and an authentication status monitor.
To use the Google provider, the first step is to create an instance of GoogleAuthProvider (or equivalent provider depending on your case), and then define an asynchronous function that calls signInWithPopup(FirebaseAuth, provider)If that call is successful, you will receive an object with the authenticated user, from which you can extract uid, displayName, photoURL and other fields. Often, you only need to work with the UID and return it to establish the global session.
For authentication using email and password, you have two key functions: createUserWithEmailAndPassword y signInWithEmailAndPasswordBoth await the opportunity to... FirebaseAuthThe email and password are required. The first creates new users, the second verifies their existence and authenticates them. Internally, Firebase handles validating the email format, password length, and other factors, returning clear errors that you can intercept in a block. try/catch and show with a simple alert or with your own notification system.
To log out, simply use signOut(FirebaseAuth)This is something you can also encapsulate in a function of your service to keep your code's API cleaner and more consistent.
Observe session changes with onAuthStateChanged
A very common problem when starting with authentication is that, even if the login works, when you reload your React app page or close and reopen the mobile app, It appears that the session has been missed.However, Firebase has default persistence of authentication state: you're simply not reading it correctly.
The solution is to use the function onAuthStateChanged from the Firebase Auth SDK. This function receives the authentication instance and a callback that will be executed every time the state changes: when the user logs in, when they log out, or when the app initializes and Firebase retrieves the saved credentials.
In a React app, the normal thing to do is to create a function, for example observeAuthState, that receives a state setter (such as setSession) and inside call onAuthStateChanged(FirebaseAuth, user => { ... })In that callback, if user is null or undefinedYou set the global session as unauthenticated; if there is a user, you save their username. uid and mark the status as authenticated.
This observer is usually shot inside a useEffect at the highest point of the app (for example, in a context) so that it runs only once when the app is launched. This ensures that even if the user reloads the browser, if Firebase has the session remembered, your global state is automatically updated and sent directly to the private part of the app without asking for credentials again.
Global authentication context in React

To avoid passing props from one component to another, a very convenient strategy in React is to create a Specific Context API for authenticationIn this way, any part of the app can know if the user is authenticated, what their uid is and what functions are available to them (login, logout, etc.) without the need for prop drilling.
Start by creating a folder src/context and inside a file, for example authContext.tsxThere you define an interface that describes what your context will expose: the professional status of the session (for example, 'checking', 'authenticated', 'no-authenticated'), the userId (or null if there is no user) and the functions to log in or log out.
Next, define an initial state, with status in 'checking' and userId in null, and create context with createContextNext, build a component AuthProvider that receives children, use useState to manage the session and call your function observeAuthState in a useEffect upon mounting.
Within this provider, it's useful to have auxiliary functions: one for Sign off that calls your logoutFirebase service and leaves the state as unauthenticated, another one for force the state to 'checking' when you start an authentication flow, and another for validate the result of a login/registration (If you receive a UID, mark it as authenticated; otherwise, call the logout command to clear any session remnants).
With that, you can implement three public actions in the context: handleLoginWithGoogle, handleLoginWithCredentials y handleRegisterWithCredentialsEach one will start the "checking," invoke the corresponding service function, and delegate the final decision to the common validation you've created. In the end, the AuthContext.Provider It will expose both the state (status, userId) and these functions, and you will wrap your app in AuthProvider in the root file (for example, in src/main.tsx).
Using context in login, registration, and home components
Once you have your authentication context ready, using it in your components is very simple. In the component Login.tsxIt matters useContext, access the AuthContext and extracts, for example, the functions handleLoginWithCredentials y handleLoginWithGoogleIn the login form submission, you will call the first one, passing the email and password from your hook. useFormwhile the exclusive “Sign in with Google” button will launch its second version at its event onClick.
For the component Register.tsx You'll do something very similar, but using only handleRegisterWithCredentialsThe form will ask for the same fields (email and password), or some more if you want, and when you submit, the context logic will be responsible for creating the user and updating the global status.
In the main component App.tsxYou will also consume the context to read the professional status and the userIdWhile the status is 'checking', you can display a small loading message or transition screen. When the status changes, if the user is authenticated and has a valid userId, you will display a component like HomePage where you display content only to logged-in users (for example, their UID and a logout button that calls handleLogOutIf the status indicates that it is not authenticated, you render a component of type AuthPage that includes your Login and Register forms.
Registration and login with Firebase Auth in React Native
In React Native, although the technical structure differs from the web, the conceptual pattern is the same. On the registration screen (RegistrationScreen), you'll have a local state for fullName, Email, Password y confirmPasswordWhen you click the create account button, you check that the passwords match and, if everything looks right, you call firebase.auth().createUserWithEmailAndPassword(email, password).
Once Firebase creates the account, you can save additional user information in Firestore, in a collection usersby setting the document ID to the UID returned by Firebase. This gives you a central location to store the data. full name, profile picture, or other personalized information that don't fit in the standard authentication table. If the entire string works, you navigate to the home screen by passing the user object as a parameter.
On the login screen (LoginScreen), you also import Firebase and use firebase.auth().signInWithEmailAndPassword(email, password)Once you receive the response with the user, you can read their extended data from Firestore using the UID, and if that document exists, navigate to the Home page with that user in the navigation bar. If the query returns nothing because the user has been deleted from Firestore, you will notify the user and prevent further processing.
Session persistence in React Native with onAuthStateChanged
Just like on the web, in React Native it's very annoying for the user to have to log in every time they open the app. Firebase Auth also takes care of remembering the login and allows you to retrieve the current user using the same login. onAuthStateChangedIn this environment, the logic is usually placed in the component App or in a context similar to that of the web.
You use a useEffect which runs only once when mounting the component and within which you call firebase.auth().onAuthStateChangedIf you receive a user in the callback, you look for their corresponding document in the collection. users from Firestore, and when you get it, you update the status user and uncheck the loading flag. If there is no authenticated user, simply set loading to false and leave user as null, which will cause the navigation tree to display the public screens.
This pattern ensures that if the user opened the app a while ago and left it in the background, or if they close and reopen it, it will continue to appear directly on the Home screen as long as their session token remains valid, greatly improving the user experience without you having to manually manage tokens.
Reading and writing data to Firestore from React Native
Once the authentication part is resolved, it's time to do something useful with the database. A very typical example is creating a Home screen that allows the user Add text elements to a collection and list them in real time.Imagine that those items are tasks, notes, or quick posts, and that you only want him to see his own.
On the Home screen, you declare a state for the current text (entityText) and another for the list of entities (entitiesYou also create a reference to the Firestore collection, for example entityRef = firebase.firestore().collection('entities'), and you save the authenticated user's ID (for example. userID = props.extraData.id).
within a useEffectYou set up a real-time listener with entityRef.where('authorID', '==', userID).orderBy('createdAt', 'desc').onSnapshot(...)This callback is triggered whenever something changes in the documents that meet that condition. You iterate through the documents in the snapshot, build an array with the content of each entity, include the document ID, and update the state. entities with that new array. Thanks to that, the FlatList you use to display the entities will be rendered with the most recent data.
To add new elements, you create a function onAddButtonPress which verifies that entityText not empty, generate a server timestamp with firebase.firestore.FieldValue.serverTimestamp() and call entityRef.add({ text: entityText, authorID: userID, createdAt: timestamp })If the operation is successful, you can clear the text field and close the keyboard; Firestore will take care of launching a new snapshot that will make the new item appear in the list.
When using combined filters and sorting, Firestore may require you to create a composite indexIf that happens, you'll see a notification in the logs with a direct link to the Firebase console to create that index with a single click. Once created, queries that mix where y orderBy They will work without problems.
Connect React web with Firebase Realtime Database
In addition to Firestore, you might need to work with the Firebase Realtime Database from a web app built with React. The general flow is: you initialize Firebase with your project configuration, import the library of firebase/database and you create references to the nodes that interest you, such as object/nameIt's very useful for scenarios where You want to see changes reflected instantly in the interface..
Imagine that in the Firebase console you create a node object with a property name whose value is “Carlos”. In your React app you define a local state name with an initial value, for example “Pepe”, and you render a <h1>{this.state.name}</h1> (if you use class components) or the equivalent with hooks.
In the life cycle method componentDidMount (or in a useEffect with empty dependency on functional components), you create a reference with firebase.database().ref().child('object').child('name') and you add a listener of type on('value', snapshot => { ... })Each time the value event is triggered, you will receive a snapshot of the node's current value; you do a setState to snapshot.val() React handles the re-rendering of the text. You change the name in the Firebase console and see it instantly in your browser.
To make this work without authentication, you need to adjust the settings in the Realtime Database panel. security rules This allows public read and write access during development (for example, by setting `read` and `write` to `true`). However, it's important to restrict these rules in production, typically by requiring user authentication or applying conditions on the path or UID to prevent your database from being open to the public.
Final considerations
With this basic pattern you can build countless use cases: presence indicators, shared counters, real-time dashboards, or small demo apps where interactivity between customers needs to be immediate.
As you can see, combining React (both web and mobile) with Firebase allows you to quickly build projects with authentication, databases, and real-time logic, leveraging... hooks, contexts, and real-time listeners to synchronize the visual state with what's happening on the Google-managed backend. This combination of rapid development and scalability means that, for many projects, it doesn't make sense to reinvent the entire server layer when you can focus on the user experience and let Firebase handle the rest.