i estás montando una aplicación con React o React Native y quieres añadirle login, base de datos en tiempo real o simplemente dejar de preocuparte por el backend, Firebase es una de las opciones más cómodas y potentes que tienes ahora mismo. Te permite tener autenticación, base de datos, almacenamiento de archivos y mucho más sin levantar ni una sola API propia.
En este artículo vamos a ver, paso a paso, cómo conectar una app de React (y también React Native / Expo) con Firebase, cómo estructurar el proyecto, configurar la autenticación por email y por Google, persistir la sesión de usuario y leer/escribir datos tanto en Firestore como en la Realtime Database. Lo haremos con ejemplos reales y código comentado, pero explicándolo en un lenguaje cercano para que puedas seguirlo aunque no seas un ninja todavía.
¿Qué es Firebase y por qué encaja tan bien con React?
Firebase es un Backend as a Service de Google que te da una serie de servicios ya listos para usar: autenticación, base de datos en tiempo real, Firestore (base de datos NoSQL documental), almacenamiento de archivos, analytics, herramientas de crecimiento, monetización, etc. Nació como una base de datos en tiempo real, pero tras varias iteraciones se ha convertido en una plataforma backend muy completa.
En lugar de montarte un servidor propio, diseñar tu API, gestionar la infraestructura y escalarla, con Firebase puedes conectar tu app de React directamente al backend mediante su SDK oficial. Eso significa que muchas de las tareas típicas de backend (auth, CRUD, reglas de seguridad, notificaciones, etc.) se resumen a unas cuantas llamadas a funciones JavaScript bien documentadas.
La integración con React es muy natural porque Firebase expone sus datos en formato JSON y sus SDKs están pensados para trabajar en cliente. Con React simplemente lees esos datos, los metes en el estado de tus componentes y dejas que la librería se encargue de renderizar todo cada vez que algo cambie. Cuando usas sus listeners en tiempo real, cada actualización en la base de datos dispara un re-render automático, lo cual encaja como un guante con el modelo declarativo de React.
Crear y configurar un proyecto de Firebase
Antes de empezar a escribir código en React, hay que tener listo el entorno en Firebase. El proceso es muy parecido tanto si vas a usarlo desde una app web en React como desde React Native o Expo. En todos los casos, el primer paso es crear el proyecto en la consola de Firebase.
Entra en https://firebase.google.com/, inicia sesión con tu cuenta de Google y accede a la consola. Desde ahí crea un nuevo proyecto, ponle un nombre reconocible (por ejemplo, “react-firebase” o “auth-firebase-react”) y selecciona la región que tenga más sentido para la audiencia de tu aplicación.
Una vez creado el proyecto, Firebase te llevará al panel principal. Verás varias opciones para añadir aplicaciones: iOS, Android y Web. En una app web con React seleccionas el icono de la web, mientras que para React Native puedes registrar apps iOS y/o Android según necesites. El objetivo en todos los casos es obtener una configuración de Firebase con claves como apiKey, authDomain, projectId y similares.
La consola te mostrará un fragmento de código con algo parecido a:
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);
En React web realmente solo necesitas el objeto de configuración y la llamada a initializeApp** usando el SDK modular actual. Más adelante verás cómo encajar esto en tu estructura de proyecto.
Elegir base de datos: Realtime Database vs Firestore
Firebase te ofrece dos tipos de base de datos principales: la Realtime Database y Cloud Firestore. Ambas son NoSQL, pero tienen diferencias importantes en modelo de datos, consultas y forma de facturar.
La Realtime Database es una base de datos en formato JSON gigante, en la que todo cuelga de un único árbol. Es ideal cuando necesitas actualizaciones muy rápidas y sincronización en tiempo real sencilla. La estructura se basa en nodos y rutas, y accedes a ellos con referencias como firebase.database().ref('object/name'). Es la opción clásica si quieres algo tipo chat, presencia de usuarios o datos muy simples.
Firestore, por su parte, organiza la información en colecciones y documentos. Cada documento tiene campos y puedes anidar subcolecciones en su interior. Permite consultas más complejas, índices compuestos, ordenaciones y filtros combinados. Es perfecta para aplicaciones un poco más grandes donde necesites consultas flexibles, escalabilidad y reglas de seguridad más expresivas.
Ambas bases de datos pueden usarse desde React sin problema, e incluso en la misma app. Por ejemplo, puedes guardar usuarios, posts o tareas en Firestore y aprovechar la Realtime Database para algún dato muy dinámico que quieras escuchar de forma constante. Lo importante es que tengas claro que en React basta con escuchar los cambios y actualizar el estado, el resto lo hace Firebase por ti.
Crear una app React Native / Expo con Firebase

Si en tu caso trabajas con React Native, puedes integrar Firebase usando el SDK Web de Firebase, que es perfectamente compatible con proyectos creados con Expo o con el CLI oficial de React Native. De esta manera no te atas a librerías intermedias y te mantienes en lo que Google soporta oficialmente.
Para empezar con Expo, instala globalmente el CLI de Expo desde la terminal usando npm install -g expo-cli. Después, crea un nuevo proyecto de React Native con expo init, elige una plantilla básica (por ejemplo, “blank” con workflow gestionado) y arranca la app con yarn ios o yarn android. Expo te mostrará un código QR que puedes escanear con la cámara en iOS o con la app de Expo en Android para ver tu proyecto en el dispositivo.
Una vez que tienes tu app base corriendo, añade las dependencias necesarias: en primer lugar el propio SDK de Firebase, con yarn add firebase. Después puedes incorporar librerías de navegación como @react-navigation/native y @react-navigation/stack, junto con los paquetes adicionales que necesitan en React Native (gesture-handler, reanimated, screens, safe-area-context, etc.) para gestionar los flujos entre pantallas de login, registro y home.
Es también muy útil instalar algunos componentes auxiliares para la UI móvil, por ejemplo react-native-keyboard-aware-scroll-view para manejar bien el teclado en formularios, y librerías como base-64 para suplir funciones globales que faltan en algunos runtimes móviles (btoa, atob, etc.). Todo esto se añade con un único comando de instalación usando yarn en tu proyecto.
Configurar Firebase en React / React Native
La configuración de Firebase la vas a centralizar en un único archivo, de forma que el resto de la aplicación solo tenga que importar una instancia ya inicializada. Crea, por ejemplo, una carpeta src/firebase y dentro un archivo de configuración, como config.js (o config.ts en TypeScript).
En ese archivo importa las funciones necesarias del SDK de Firebase y define tu objeto de configuración con los valores que te dio la consola de Firebase. En proyectos React Native que utilizan el SDK antiguo puedes ver algo como:
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 };
El proyectos web con Vite y TypeScript se suele usar la versión modular del SDK de Firebase 9, y es buena práctica colocar los valores sensibles en variables de entorno. Por ejemplo, puedes crear un archivo .env en la raíz y definir claves como VITE_FIREBASE_API_KEY, VITE_FIREBASE_AUTH_DOMAIN, etc. Luego, en el archivo de configuración, construyes el objeto a partir de import.meta.env['VITE_FIREBASE_API_KEY'] y similares.
Sea cual sea el enfoque, el patrón es el mismo: inicializas solo una vez la app de Firebase y exportas esa instancia (o bien exportas objetos concretos como FirebaseAuth, Firestore o Realtime Database) para usarla fácilmente en el resto del proyecto.
Arquitectura básica de pantallas: login, registro y home
Cuando integras autenticación en una app de React Native, una estructura muy habitual es tener tres pantallas principales: Login, Registro y Inicio (Home). Además, puedes centralizar la lógica de navegación en un único componente raíz, normalmente App.js.
En React Native con React Navigation, lo típico es crear una carpeta src/screens con subcarpetas por pantalla (LoginScreen, RegistrationScreen, HomeScreen) y un archivo de índice que exporte cada una de ellas. Luego, en App.js, creas un stack navigator que muestre una u otra pantalla según exista usuario autenticado o no.
La idea es guardar en el estado del componente App un user (o null) y un flag de loading. Mientras se está comprobando el estado de autenticación, puedes mostrar una pantalla vacía o un loader. Cuando sabes si el usuario ha iniciado sesión, decides qué rutas enseñar: si hay usuario, muestres la pantalla de inicio, si no lo hay, las pantallas de login y registro.
Visualmente, las pantallas de login y registro son formularios sencillos con campos como email, contraseña y, en el caso del registro, nombre completo o confirmación de contraseña. Para mejorar la experiencia en móvil, se suele envolver todo con un KeyboardAwareScrollView para que el teclado no tape los inputs. El Home, por su parte, puede empezar como una vista mínima (un simple texto) y más adelante evolucionar a la parte de la app donde ya lees y escribes datos de Firestore.
Diseño y gestión de formularios con hooks en React
En una aplicación de React web con TypeScript, una forma limpia de gestionar formularios de autenticación es encapsular la lógica en un custom hook. Por ejemplo, puedes crear useForm.tsx en una carpeta src/hooks, que reciba un estado inicial genérico (un objeto con las propiedades del formulario) y devuelva tanto los valores como una función para manejar los cambios.
Ese hook puede usar useState internamente para almacenar el formulario y exponer una función handleChange que reciba el evento del input, lea el atributo name del elemento y actualice la propiedad correspondiente en el estado. De este modo, tener los name bien puestos en los inputs (por ejemplo, name="email" y name="pass") es clave para que todo funcione.
En el componente de login, por ejemplo, llamarías a useForm({ email: '', pass: '' }) y obtendrías el email, el pass, el objeto form y la función handleChange. Cada input tendría su value y onChange ligados a esos valores y a la función del hook. Al enviar el formulario, tendrías un handleSubmit que hace e.preventDefault() y después llama a la lógica de autenticación con Firebase.
Lo mismo se aplica al formulario de registro; incluso podrías extraer un componente de formulario reutilizable, dado que muchas veces solo cambian el texto de los botones y el callback que se ejecuta en el submit, mientras la estructura básica es igual.
Configurar la autenticación en Firebase
Para que React pueda autenticarse contra Firebase, en la consola de Firebase hay que habilitar los proveedores de autenticación. Desde la sección de Autenticación, entra en la pestaña de métodos de acceso (Sign-in method) y activa el correo electrónico / contraseña y, si te interesa, el proveedor de Google.
En el proveedor de correo electrónico/contraseña basta con marcarlo como habilitado y guardar. En el de Google, además de habilitarlo, tendrás que seleccionar el correo que se usará por defecto. A partir de ahí, tu proyecto quedará preparado para aceptar inicios de sesión con ambos métodos.
En la pestaña de usuarios (Users) de la misma sección irás viendo cómo se registran las cuentas nuevas que se creen desde tu aplicación, ya sea con email y contraseña o mediante Google. Es un buen lugar para comprobar que la integración campo a campo está funcionando como toca.
Funciones de autenticación con Firebase en React
En una app web con React y TypeScript es recomendable agrupar toda la lógica de autenticación en un archivo de servicios, por ejemplo src/firebase/services.ts. Ahí puedes tener funciones específicas para cada acción: login con Google, login con credenciales, registro, cierre de sesión y un observador del estado de autenticación.
Para usar el proveedor de Google, lo primero es crear una instancia de GoogleAuthProvider (o proveedor equivalente según tu caso), y después definir una función asíncrona que llame a signInWithPopup(FirebaseAuth, provider). Si esa llamada tiene éxito, recibirás un objeto con el usuario autenticado, del que puedes extraer uid, displayName, photoURL y otros campos. Muchas veces te basta trabajar con el uid y devolverlo para establecer la sesión global.
Para la autenticación mediante email y contraseña tienes dos funciones clave: createUserWithEmailAndPassword y signInWithEmailAndPassword. Ambas esperan la instancia de FirebaseAuth, el email y la contraseña. La primera crea usuarios nuevos, la segunda verifica que existan y los autentica. Internamente, Firebase se encarga de validar el formato de email, longitud de la contraseña y demás, devolviendo errores claros que puedes interceptar en un bloque try/catch y mostrar con un simple alert o con tu propio sistema de notificaciones.
Para cerrar sesión solo tienes que usar signOut(FirebaseAuth), algo que también puedes encapsular en una función de tu servicio para mantener la API de tu código más limpia y coherente.
Observar los cambios de sesión con onAuthStateChanged
Un problema muy típico cuando empiezas con autenticación es que, aunque el login funcione, al recargar la página de tu app React o al cerrar y volver a abrir la app móvil, aparenta que se ha perdido la sesión. Sin embargo, Firebase tiene persistencia por defecto del estado de autenticación: simplemente no la estás leyendo correctamente.
La solución es utilizar la función onAuthStateChanged del SDK de Firebase Auth. Esta función recibe la instancia de autenticación y un callback que se ejecutará cada vez que cambie el estado: cuando el usuario inicia sesión, cuando la cierra o cuando la app se inicializa y Firebase recupera las credenciales guardadas.
En una app React lo normal es crear una función, por ejemplo observeAuthState, que reciba un setter de estado (como setSession) y dentro llame a onAuthStateChanged(FirebaseAuth, user => { ... }). En ese callback, si user es null o undefined, estableces la sesión global como no autenticada; si hay usuario, guardas su uid y marcas el estado como autenticado.
Este observador se suele disparar dentro de un useEffect en el punto más alto de la app (por ejemplo, en un contexto) para que se ejecute una sola vez cuando la aplicación se monta. Así consigues que, aunque el usuario recargue el navegador, si Firebase tiene la sesión recordada, tu estado global se actualice automáticamente y lo envíes directamente a la parte privada de la app sin pedirle de nuevo las credenciales.
Contexto global de autenticación en React

Para no ir pasando props de un componente a otro, una estrategia muy cómoda en React es crear un Context API específico para la autenticación. De esa forma, cualquier parte de la app puede saber si el usuario está autenticado, cuál es su uid y qué funciones tiene disponibles (login, logout, etc.) sin necesidad de prop drilling.
Empieza creando una carpeta src/context y dentro un archivo, por ejemplo authContext.tsx. Ahí defines una interfaz que describa lo que va a exponer tu contexto: el status de la sesión (por ejemplo, ‘checking’, ‘authenticated’, ‘no-authenticated’), el userId (o null si no hay usuario) y las funciones para iniciar o cerrar sesión.
A continuación, define un estado inicial, con status en ‘checking’ y userId en null, y crea el contexto con createContext. Después, construye un componente AuthProvider que reciba children, use useState para gestionar la sesión y llame a tu función observeAuthState en un useEffect al montarse.
Dentro de este proveedor es útil tener funciones auxiliares: una para cerrar sesión que llame a tu servicio logoutFirebase y deje el estado como no autenticado, otra para forzar el estado a ‘checking’ cuando arranques un flujo de autenticación, y otra para validar el resultado de un login/registro (si recibes un uid, marcas como autenticado; si no, llamas a la de logout para limpiar cualquier resto de sesión).
Con eso, puedes implementar tres acciones públicas en el contexto: handleLoginWithGoogle, handleLoginWithCredentials y handleRegisterWithCredentials. Cada una arrancará el “checking”, invocará la función de servicio correspondiente y delegará la decisión final en la validación común que has creado. Al final, el AuthContext.Provider expondrá tanto el estado (status, userId) como estas funciones, y envolverás tu app en AuthProvider en el archivo raíz (por ejemplo, en src/main.tsx).
Uso del contexto en componentes de login, registro y home
Una vez tengas listo el contexto de autenticación, usarlo en tus componentes es muy sencillo. En el componente Login.tsx, importa useContext, accede al AuthContext y extrae, por ejemplo, las funciones handleLoginWithCredentials y handleLoginWithGoogle. En el submit del formulario de login llamarás a la primera, pasándole el email y la contraseña desde tu hook useForm, mientras que el botón exclusivo de “Iniciar sesión con Google” lanzará la segunda en su evento onClick.
Para el componente Register.tsx harás algo muy similar, pero usando únicamente handleRegisterWithCredentials. El formulario pedirá los mismos campos (email y password), o algunos más si quieres, y al realizar el submit, la lógica del contexto será la responsable de crear el usuario y actualizar el estado global.
En el componente principal App.tsx, también consumirás el contexto para leer el status y el userId. Mientras el status sea ‘checking’, puedes mostrar un pequeño mensaje de carga o pantalla de transición. Cuando el status cambie, si está autenticado y hay un userId válido, mostrarás un componente tipo HomePage donde enseñes contenido solo para usuarios logueados (por ejemplo, su uid y un botón de cerrar sesión que llame a handleLogOut). Si el status indica que no está autenticado, renderizas un componente tipo AuthPage que incluya tus formularios de Login y Register.
Registro e inicio de sesión con Firebase Auth en React Native
En React Native, aunque la estructura técnica difiere de la web, el patrón conceptual es el mismo. En la pantalla de registro (RegistrationScreen), tendrás un estado local para fullName, email, password y confirmPassword. Al pulsar el botón de crear cuenta, compruebas que las contraseñas coinciden y, si todo cuadra, llamas a firebase.auth().createUserWithEmailAndPassword(email, password).
Una vez que Firebase crea la cuenta, puedes guardar información adicional del usuario en Firestore, en una colección users, colocando como id del documento el uid que devuelve Firebase. De esta manera tienes un punto central donde guardar nombre completo, foto de perfil u otros datos personalizados que no caben en la tabla de autenticación estándar. Si toda la cadena funciona, navegas a la pantalla de inicio pasando el objeto de usuario como parámetro.
En la pantalla de login (LoginScreen), importas igualmente Firebase y usas firebase.auth().signInWithEmailAndPassword(email, password). Una vez recibes la respuesta con el usuario, puedes leer sus datos ampliados desde Firestore utilizando el uid, y si ese documento existe, navegar a Home con ese usuario en la navegación. Si la consulta no devuelve nada porque el usuario ha sido borrado en Firestore, avisarás al usuario y evitarás seguir adelante.
Persistencia de sesión en React Native con onAuthStateChanged
Al igual que en la web, en React Native es muy molesto que el usuario tenga que iniciar sesión cada vez que abre la app. Firebase Auth también se encarga de recordar el inicio de sesión y permite recuperar el usuario actual mediante el mismo onAuthStateChanged. En este entorno, la lógica suele colocarse en el componente App o en un contexto similar al de la web.
Utilizas un useEffect que se ejecuta una sola vez al montar el componente y dentro llamas a firebase.auth().onAuthStateChanged. Si en el callback recibes un usuario, buscas su documento correspondiente en la colección users de Firestore y, cuando lo obtienes, actualizas el estado user y desmarcas el flag de loading. Si no hay usuario autenticado, simplemente pones loading en false y dejas user en null, lo que provocará que el árbol de navegación muestre las pantallas públicas.
Con este patrón consigues que, si el usuario abrió la app hace un rato y la dejó en segundo plano, o si la cierra y la vuelve a abrir, siga apareciendo directamente en la pantalla Home mientras su token de sesión siga siendo válido, lo que mejora muchísimo la experiencia de uso sin que tú tengas que manejar tokens manualmente.
Lectura y escritura de datos en Firestore desde React Native
Una vez resuelta la parte de autenticación, toca hacer algo útil con la base de datos. Un ejemplo muy típico es crear una pantalla Home que permita al usuario añadir elementos de texto a una colección y listarlos en tiempo real. Imagina que esos elementos son tareas, notas o publicaciones rápidas, y que quieres que solo vea las suyas.
En la pantalla Home, declaras un estado para el texto actual (entityText) y otro para la lista de entidades (entities). También creas una referencia a la colección de Firestore, por ejemplo entityRef = firebase.firestore().collection('entities'), y guardas el id del usuario autenticado (por ejemplo. userID = props.extraData.id).
Dentro de un useEffect, estableces un listener en tiempo real con entityRef.where('authorID', '==', userID).orderBy('createdAt', 'desc').onSnapshot(...). Este callback se dispara cada vez que cambia algo en los documentos que cumplen esa condición. Recorres los documentos del snapshot, construyes un array con el contenido de cada entidad, incluyes el id del documento y actualizas el estado entities con ese nuevo array. Gracias a eso, el FlatList que uses para mostrar las entidades se renderizará con los datos más recientes.
Para añadir nuevos elementos, creas una función onAddButtonPress que verifica que entityText no esté vacío, genera un timestamp de servidor con firebase.firestore.FieldValue.serverTimestamp() y llama a entityRef.add({ text: entityText, authorID: userID, createdAt: timestamp }). Si la operación tiene éxito, puedes limpiar el campo de texto y cerrar el teclado; Firestore se encargará de lanzar un nuevo snapshot que hará aparecer el nuevo elemento en la lista.
Es posible que al usar filtros y ordenaciones combinados, Firestore te exija crear un índice compuesto. Si eso pasa, en los logs verás un aviso con un enlace directo a la consola de Firebase para crear ese índice con un solo clic. Una vez creado, las consultas que mezclan where y orderBy funcionarán sin problemas.
Conectar React web con Firebase Realtime Database
Además de Firestore, puedes necesitar trabajar con la base de datos Realtime de Firebase desde una app web hecha con React. El flujo general es: inicializas Firebase con la configuración de tu proyecto, importas la librería de firebase/database y creas referencias a los nodos que te interesen, como object/name. Viene muy bien para escenarios donde quieres ver cambios reflejados al instante en la interfaz.
Imagina que en la consola de Firebase creas un nodo object con una propiedad name cuyo valor sea “Carlos”. En tu app React defines un estado local name con un valor inicial, por ejemplo “Pepe”, y renderizas un <h1>{this.state.name}</h1> (si usas componentes de clase) o el equivalente con hooks.
En el método del ciclo de vida componentDidMount (o en un useEffect con dependencia vacía en componentes funcionales), creas una referencia con firebase.database().ref().child('object').child('name') y añades un listener de tipo on('value', snapshot => { ... }). Cada vez que se dispare el evento value, recibirás un snapshot con el valor actual del nodo; haces un setState con snapshot.val() y React se encarga de re-renderizar el texto. Cambias el nombre en la consola de Firebase y lo ves al instante en tu navegador.
Para que esto funcione sin autenticación, en el panel de Realtime Database debes ajustar las reglas de seguridad permitiendo lectura y escritura públicas durante el desarrollo (por ejemplo, estableciendo read y write a true). Eso sí, es importante que en producción restrinjas estas reglas, normalmente exigiendo que el usuario esté autenticado o aplicando condiciones sobre la ruta o el uid para no dejar tu base de datos abierta al mundo.
Ultimas consideraciones
Con este patrón básico puedes construir infinidad de casos de uso: indicadores de presencia, contadores compartidos, paneles en tiempo real o pequeñas apps de demostración donde la interactividad tenga que ser inmediata entre clientes.
Como ves, combinar React (tanto en web como en móvil) con Firebase te permite levantar proyectos con autenticación, base de datos y lógica en tiempo real de manera muy ágil, apoyándote en hooks, contextos y listeners en tiempo real para sincronizar el estado visual con lo que ocurre en el backend gestionado por Google. Esa mezcla de rapidez de desarrollo y escalabilidad hace que, para muchos proyectos, no tenga sentido reinventar toda la capa de servidor cuando puedes centrarte en la experiencia de usuario y dejar que Firebase se encargue del resto.