◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-05-06Intermediate

Adding Expo Dev Client to Your Rork App

Added a native module to a Rork app and Expo Go no longer opens it? Here is how to set up Expo Dev Client (a custom development build), including the prebuild trap, when a rebuild is needed, and how EAS Update fits in.

Expo Dev ClientRork584React Native239Native Modules5Expo219EAS Build22Dev Environment

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 storage
  • react-native-purchases (RevenueCat): subscription billing
  • react-native-vision-camera: advanced camera
  • react-native-keychain: secure credential storage
  • @react-native-firebase/*: native Firebase SDKs
  • react-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:configure

eas 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 android

Because 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-client

Depending 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 changedRebuildNote
JavaScript or TypeScript only (screens, logic)Not neededSave and reload
Native module added, removed, or version-bumpedNeededThe new native code is not in the existing build
App name, icon, permissions, URL schemes, or other app.json changesNeededThey must be applied to the native side
Expo SDK version upgradeNeededAlso run npx expo install --check to verify dependencies
Metro or environment variables onlyUsually not neededRestarting 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.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⬡ Dev Tools2026-09-21
A build that stops with exit code 0 — the flag that silenced the log, and the check that let an empty file through
Two reports landed in the same week: eas build --local stopping with exit code 0 but produced no further output, and a zero-byte stub that never got embedded. Both came down to settings that reduce output. Here is how to audit your own scripts.
⬡ Dev Tools2026-09-07
Adding .easignore stops EAS from reading .gitignore — count what actually ships to the build
EAS Build decides what to upload from .gitignore, and the moment you add .easignore the two swap places. Here is how I count the bundled files before sending, plus a measured result: once a parent directory is excluded, an exclamation mark cannot bring a file back.
⬡ Dev Tools2026-09-04
EAS secret visibility does not keep a value out of your app — deciding prefix and visibility separately
The EXPO_PUBLIC_ prefix decides what ships inside your app; EAS visibility decides who can read it. Why stacking them blanks a value on OTA updates, and how to check your build.