You add react-native-mmkv to the code Rork generated, save, and Expo Go won't open the app anymore. After the splash screen a red screen appears. Depending on the library and version, the message reads "Native module cannot be null" or "Failed to create a new MMKV instance." You reread the code, find nothing wrong, and asking Rork's AI to fix it changes nothing.
That red screen is not a Rork bug or an Expo bug. Expo Go can only run the native modules that were bundled with the Expo SDK ahead of time. The moment you add a library that needs its own native code, Expo Go has done its job. What you need next is Expo Dev Client, often called a "custom development build."
This article covers how to add Dev Client to a Rork-generated app and where people usually stumble. If the AI keeps rewriting code without fixing anything, the cause is often the runtime environment rather than the code, so I have also included a way to tell the two apart.
Expo Go vs. Expo Dev Client
Let me set the framing first.
Expo Go is a generic preview app distributed through the App Store and Google Play. It runs your JavaScript and the native modules included in the Expo SDK, but it has no third-party native code that you added yourself.
Expo Dev Client is a development app built specifically for your project. Its contents are close to your production build, with every native module you added included. The differences are that it can load JavaScript from the Metro dev server and that it exposes the developer menu.
It helps to think of Dev Client as "your production build plus a reload loop." Once you build it and install it on a device, JavaScript-only changes still show up the usual way: save and reload.
Libraries That Commonly Force the Switch
These are libraries Rork users often add that frequently will not run in Expo Go:
react-native-mmkv: fast local storagereact-native-purchases(RevenueCat): subscription billingreact-native-vision-camera: advanced camerareact-native-keychain: secure credential storage@react-native-firebase/*: native Firebase SDKsreact-native-onesignal: push notifications (see also Integrating OneSignal with Rork)
Some libraries, such as @shopify/react-native-skia, are bundled with Expo Go in certain SDK versions. Whether a library works in Expo Go is best checked in the official documentation for the SDK version you use, not from memory. While you only use things provided as part of the Expo SDK, such as expo-image, expo-secure-store, and expo-notifications, you can keep developing in Expo Go.
Step 1: Tidy the Config (Prebuild Is Not Required)
Building Dev Client with EAS Build is the easiest route. First, confirm that app.json has the identifiers the build needs:
{
"expo": {
"name": "MyRorkApp",
"slug": "my-rork-app",
"ios": {
"bundleIdentifier": "com.yourcompany.myrorkapp"
},
"android": {
"package": "com.yourcompany.myrorkapp"
}
}
}By convention the identifier is your domain written in reverse. It is hard to change after a store release, so decide it early.
One common misunderstanding deserves a note here. npx expo prebuild generates ios/ and android/ from app.json, but if you only build with EAS Build you do not need to run it locally. EAS runs it for you when needed.
The case to watch is when you ran prebuild locally and committed ios/ and android/. In that state EAS Build treats those folders as the source of truth, and later edits to app.json no longer reach the build. If you changed a setting and it never shows up, check this first.
# Only when you want to inspect the native side locally
npx expo prebuild --clean--clean deletes and regenerates ios/ and android/. If you have edited native code by hand, back it up before running it.
Step 2: Install expo-dev-client and Run an EAS Build
Now install Dev Client itself and create the build configuration:
npx expo install expo-dev-client
npm install -g eas-cli
eas login
eas build:configureeas build:configure creates eas.json interactively. Add a development profile to it:
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"ios": {
"simulator": true
}
},
"preview": {
"distribution": "internal"
},
"production": {}
}
}developmentClient: true marks the build as a Dev Client. Adding ios.simulator: true targets the iOS simulator; remove it if you want to install on a physical device. A device build for iOS requires an Apple Developer account and a registered device.
# iOS simulator
eas build --profile development --platform ios
# Android (device or emulator)
eas build --profile development --platform androidBecause the build runs in the cloud, you can produce an iOS simulator build without owning a Mac. Device builds still need signing set up. Build time depends on the queue: roughly ten-plus minutes, and longer when it is busy.
Step 3: Launch Dev Client and Start Working
Once the build is installed on a device or simulator, start the dev server:
npx expo start --dev-clientDepending on the CLI version, a project with expo-dev-client installed starts in Dev Client mode even without the flag. Keeping the flag makes your intent explicit and avoids accidentally launching a server for Expo Go. Scan the QR code from Dev Client, or press i (iOS) or a (Android) in the terminal for the simulator.
Which Changes Need a Rebuild
The hardest call with Dev Client is "does this change need a new build?" Use this table as a guide.
| What changed | Rebuild | Note |
|---|---|---|
| JavaScript or TypeScript only (screens, logic) | Not needed | Save and reload |
| Native module added, removed, or version-bumped | Needed | The new native code is not in the existing build |
App name, icon, permissions, URL schemes, or other app.json changes | Needed | They must be applied to the native side |
| Expo SDK version upgrade | Needed | Also run npx expo install --check to verify dependencies |
| Metro or environment variables only | Usually not needed | Restarting the dev server is normally enough |
If the native side changed and you skipped the rebuild, you get crashes right after launch, or only the new module coming back as null. Fixing the JavaScript will not help in that case.
EAS Build Quotas and Local Builds
EAS Build has monthly build allowances that vary by plan. Exact numbers and prices change, so check the current EAS pricing page. During a stretch where you swap native modules daily, the allowance can run out quickly.
For that stretch you can build on your own machine:
eas build --profile development --platform ios --local--local runs the build on your Mac. It needs Xcode and related tooling, but you stop worrying about counts. Note that local iOS builds run only on macOS.
Using It Together with EAS Update
If you use EAS Update (OTA updates), watch the runtime version and channels. When development and production builds point at the same channel, Dev Client may fetch an older production JavaScript bundle, and a bug you already fixed can appear to come back.
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"channel": "development"
},
"production": {
"channel": "production"
}
}
}Separating channels per profile in eas.json is easier to manage. Keep runtimeVersion in app.json unchanged as long as the native side is unchanged. When you add a native module, bump the runtime version as well, so that incompatible updates never reach older builds.
Triage Order
If the app crashes right after launch even after setting this up, run through these four checks in order before digging into the cause:
- After adding the native module, did you really rebuild and reinstall that build on the device?
- Is the Dev Client left on the device or simulator the latest build? Old ones tend to linger.
- Is the dev server running with
--dev-client? Confirm you are not looking at an Expo Go screen. - If you use EAS Update, is the channel Dev Client reads the one you intended?
Running npx expo-doctor also helps. It lists dependency version mismatches and configuration conflicts in one pass, and one run before reading logs speeds up triage.
Why Rork Apps End Up Here
Code generated by Rork tends to start inside the range Expo Go can handle. That appears to favor an experience where you run something and check it right away, which is sensible as a first step.
Once you start thinking seriously about release, features involving native modules multiply: billing, advanced push notifications, fast storage. Hitting a red screen and going in circles asking the AI to fix it is a common path. Once you know the cause is the environment, you can separate what to ask the AI to change from what you need to set up yourself.
Switching to Dev Client when release comes into view makes later work easier. The App Store Connect submission walkthrough and choosing among local storage options both assume Dev Client, so they are worth reading alongside this one.
Next Step
Once the setup is done, add just one small native module and take it all the way from build to launch. Something with a narrow blast radius, like react-native-mmkv, works well. After one full pass, the rebuild decision and the red-screen triage start to feel natural.
From there, moving on to larger libraries such as RevenueCat or push notifications makes it much easier to pin down which change caused a problem.