How to Fix "Invariant Violation: 'main' Has Not Been Registered" in React Native
Quick answer
Your React Native app crashes on launch with an error claiming a component called "main" was never registered, even though your app clearly has an entry...
Your React Native app crashes on launch with an error claiming a component called "main" was never registered, even though your app clearly has an entry component. This is a naming mismatch between what your JavaScript registers and what the native iOS or Android side expects to find — the two sides need to agree on an exact string.
The Problem
The app builds and installs fine, but crashes immediately on launch with a red error screen:
Invariant Violation: "main" has not been registered. This can happen if:
* Metro (the local dev server) is run from the wrong folder. Check if Metro is running, stop it and restart it in the current project.
* A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called.
Checking your entry file shows a registration call that looks reasonable on its own:
// index.js
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
Why It Happens
The native side (iOS's AppDelegate or Android's MainActivity) is configured with a specific string naming the component it expects React Native to have registered, and JavaScript's AppRegistry.registerComponent() call must use that exact same string. A mismatch anywhere in this chain produces this error. Common causes:
- The name in
app.jsondoesn't match the native configuration — someone renamed the app in one place (often during a rebrand or project rename) without updating the corresponding native project files. - Metro is serving a stale or cached bundle from before a rename, so the currently running JavaScript still registers the old name even though the source file was updated.
- The JavaScript bundle failed to fully execute due to an unrelated error earlier in the load process, so
registerComponentwas never actually called at all — the "main not registered" message is a downstream symptom, not the root cause, in this case. - Metro was started from the wrong project directory, especially common in a monorepo with multiple React Native apps, serving a completely different app's bundle than the one that just launched.
The Fix
First, confirm the name registered in JavaScript matches what the native side expects. Check app.json:
cat app.json
{
"name": "MyApp",
"displayName": "My App"
}
For Android, check MainActivity.java or MainActivity.kt for the registered component name:
grep "getMainComponentName" android/app/src/main/java/com/myapp/MainActivity.*
override fun getMainComponentName(): String = "MyApp"
For iOS, check AppDelegate.mm (or the Swift equivalent):
grep "moduleName" ios/MyApp/AppDelegate.mm
self.moduleName = @"MyApp";
All three — app.json's name, the Android getMainComponentName(), and the iOS moduleName — must match exactly, character for character, including case. If any differ, align them all to the same value.
If the names already match, the bundle is likely stale. Clear Metro's cache and restart it fresh:
npx react-native start --reset-cache
Rebuild and reinstall the app rather than just reloading, since a stale native build can also carry an outdated bundled JS reference:
npx react-native run-android
npx react-native run-ios
If you suspect the JavaScript bundle is failing before registration runs at all, check the Metro terminal output directly for a build-time error that might be getting masked by this more generic runtime message:
npx react-native start
Watch the terminal output while reloading the app — a red error there, rather than in the app itself, often reveals the real underlying failure.
Still Not Working?
If you're working in a monorepo or have multiple React Native projects on the same machine, confirm Metro is actually serving the project you think it is — an easy mistake when multiple terminal tabs are open across different project directories:
pwd
cat package.json | grep '"name"'
Kill any other running Metro instances that might be interfering on the same port, and restart cleanly from the correct project root:
lsof -i :8081
kill -9 <PID>
cd /correct/path/to/myapp
npx react-native start --reset-cache