Embarking on a mobile app journey with React Native, Expo, and Firebase is a common path for many developers, promising rapid development and powerful features. However, this journey can sometimes be stalled by cryptic errors. One of the most common and frustrating roadblocks is the [runtime not ready]: Error: Component auth has not been registered yet
error.
This error typically emerges during the application’s initial load, preventing it from even starting. It sends developers down a rabbit hole, searching their own code for a component named “auth” that they never created. If you’ve hit this wall, rest assured, the problem is likely not in your application logic but in the underlying configuration of your project’s bundler. This guide will walk you through understanding and resolving this issue for good.
Understanding the Root of the Problem
The error message points to an issue with Firebase Authentication initialization. It signals that the native module or component responsible for handling authentication has not been properly registered with the application’s runtime before being called. This is often not a direct fault of your code but rather a side effect of how Metro, the default JavaScript bundler for React Native, resolves package dependencies.
Recent updates in the Expo and Firebase ecosystems have introduced changes to how packages export their modules. Specifically, the issue often traces back to a feature in Metro that handles the exports
field in a package’s package.json
. While this is a modern feature intended to improve module resolution, it can sometimes conflict with how the Firebase JS SDK is structured, leading to the “auth” component failing to initialize correctly.
Let’s look at a standard implementation that can trigger this error. Your Firebase service file might look something like this:
services/firebase.js
import AsyncStorage from "@react-native-async-storage/async-storage";
import { initializeApp } from "firebase/app";
import { getReactNativePersistence, initializeAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "AIza...",
authDomain: "your-app.firebaseapp.com",
projectId: "your-app",
storageBucket: "your-app.appspot.com",
messagingSenderId: "...",
appId: "..."
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Initialize Cloud Firestore and get a reference to the service
export const db = getFirestore(app);
// Initialize Firebase Authentication
export const auth = initializeAuth(app, {
persistence: getReactNativePersistence(AsyncStorage),
});
This code is perfectly valid. It initializes the Firebase app and then sets up authentication with persistent storage. The issue isn’t with the logic, but with how the initializeAuth
module is bundled by Metro.
The Primary Solution: Adjusting Your Metro Configuration
The most reliable and direct solution is to instruct Metro to opt-out of the newer package export resolution feature. This forces it to fall back to a more traditional method of resolving modules, which is fully compatible with the current Firebase SDK.
You can achieve this by making a small addition to your metro.config.js
file at the root of your project. If this file doesn’t exist, you’ll need to create it.
1. Locate or create metro.config.js
in your project’s root directory.
2. Add the following configuration:
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
// Add this line to disable the experimental package exports feature.
config.resolver.unstable_enablePackageExports = false;
// An alternative fix for some versions is to add 'cjs' to the source extensions.
config.resolver.sourceExts.push('cjs');
module.exports = config;
3. Clear the Metro cache. This is a critical step. Changes to the Metro config are not applied until the cache is cleared. Stop your development server and restart it with the -c
flag:
expo start -c
After restarting, Metro will use the updated configuration, and the “Component auth has not been registered” error should be resolved.
Alternative Solutions and Troubleshooting
If the primary solution doesn’t work, or if you’re facing a more complex setup, here are several other steps you can take to troubleshoot the issue.
1. Clean and Reinstall Dependencies
A corrupted node_modules
folder or an out-of-sync package-lock.json
can cause a host of strange bundling issues. A clean reinstall often resolves these problems.
- Delete your
node_modules
directory and yourpackage-lock.json
file (oryarn.lock
). - Run
npm install
(oryarn
) to reinstall all dependencies from scratch. - Restart your development server, clearing the cache again (
expo start -c
).
2. Check for Conflicting Firebase Libraries
A common pitfall is having two different Firebase libraries in the same project. There are two primary ways to use Firebase in React Native:
- The Firebase JS SDK (
firebase
): A JavaScript-based library that works on the web and in React Native. This is what the code examples in this article use. - React Native Firebase (
@react-native-firebase/app
): A popular third-party library that provides thin native bindings to the Firebase SDKs on iOS and Android.
These two libraries are not designed to work together and can cause major conflicts. If you have both firebase
and @react-native-firebase/app
in your package.json
, you must choose one approach and completely remove the other. If you’ve chosen the Firebase JS SDK, ensure all @react-native-firebase/*
packages are uninstalled.
3. For TypeScript Users: Configure tsconfig.json
In some TypeScript projects, the compiler might struggle to resolve the correct type definitions for Firebase, which can indirectly lead to bundling errors. You can explicitly guide the compiler by adding a path alias to your tsconfig.json
.
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true,
"paths": {
// This line tells TypeScript where to find the correct RN type definitions for auth.
"@firebase/auth": ["./node_modules/@firebase/auth/dist/index.rn.d.ts"],
"@/*": ["./*"]
}
},
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}
This ensures that your project uses the React Native-specific type definitions for Firebase Auth, which can help prevent type-related bundling issues.