ReadyNative

Expo Go or a dev build

Which modules run in Expo Go, which need a development build, and how to make one - locally with Xcode or Android Studio, or in the cloud with EAS.

Hey - by the end of this page you'll know whether your stack runs in Expo Go, and if it doesn't, you'll have a dev build on your simulator or phone that bun run start:dev connects to.

Expo Go is the app from the App Store and Play Store. It carries a fixed set of native modules, so it opens your project in seconds with no build - as long as your stack needs nothing more. A dev build is your own app with Expo's developer tools inside: every native module you picked, your icon and bundle id, and the same fast refresh from your dev server. You build it once and rebuild only when native code changes.

Before you start

  • Tier: any. On the Free tier every module runs in Expo Go.
  • Time: none if you stay in Expo Go. A local dev build takes 10-20 minutes the first time; an EAS one about 20-40 minutes in the queue.
  • Accounts: none locally. For EAS, a free Expo account, plus the paid Apple Developer Program to install an iOS build on a real iPhone.
  • Previous tutorial: Quickstart.

1. Check what your stack needs

Six options have native code Expo Go doesn't carry:

OptionWhy it needs a dev build
storage=mmkvMMKV is a native key-value store
ui=unistylesUnistyles is a C++ style engine on Nitro Modules
payments=revenuecatStoreKit and Play Billing
payments=adaptyStoreKit and Play Billing
push=expo-notificationsRemote push - Expo Go can't receive it since SDK 53
widgets=expo-widgetsThe widget is an iOS app extension

Two more run in Expo Go with less: crash=sentry reports JS errors there but needs a dev build for native crashes, and analytics=amplitude fills in the full device context only in a dev build. Local notifications work in Expo Go. Right-to-left layout (Arabic) also needs a dev build: Expo Go resets the layout direction whenever it opens a project.

setup already made the call - look at the start script in package.json:

  • expo start --go - every module you picked runs in Expo Go. bun run start opens it there.
  • expo start --dev-client - at least one needs a dev build. bun run start targets your dev build, and Expo Go won't load the project.

On Starter and Pro, bun run doctor checks the Xcode and Android SDK toolchains only when one of your modules needs them. The Free tier has no doctor; before a local build, check by hand that xcode-select -p prints a path inside Xcode.app (iOS) and that ANDROID_HOME points at your Android SDK (Android).

You should see: --go or --dev-client in the start script. On --go, you're done - come back when you add a native module.

2. Build it locally

With Xcode (iOS) or Android Studio (Android) installed, one command generates the native project, compiles it and installs it on the simulator or emulator:

bun run ios
bun run android

These are expo run:ios and expo run:android. The first run compiles every native module from source, so it takes a while; later runs reuse the build cache. For a plugged-in phone, add --device:

bunx expo run:ios --device

The ios/ and android/ folders this creates are generated - never edit them. Native settings live in app.config.ts, readynative.config.ts and config plugins, and a rebuild regenerates the folders.

You should see: "YourApp (Dev)" installed next to any other variant, opening the Expo development launcher and then your app.

3. Or build it on EAS

No Mac, or you'd rather not install Xcode? EAS builds it in the cloud with the development profile from eas.json (developmentClient: true, internal distribution). Link the project first - Ship to TestFlight has the commands - then:

bunx eas-cli build --profile development --platform android

The Android build is an .apk that installs on any phone or emulator from the link EAS prints.

iOS needs one more step. Internal builds install only on registered devices, so register your iPhone first - the command shows a QR code to open on the phone, which installs a profile that tells EAS the device's id:

bunx eas-cli device:create
bunx eas-cli build --profile development --platform ios

A device registered after a build needs a new build. To build for the iOS Simulator instead, add a profile that extends development:

eas.json
"development-simulator": {
  "extends": "development",
  "ios": { "simulator": true }
}

and build it with --profile development-simulator.

You should see: a QR code and install link when the build finishes. On iOS, enable Developer Mode (Settings → Privacy & Security) the first time you open it.

4. Start the dev server for it

bun run start:dev

That's expo start --dev-client: the QR code opens your dev build, not Expo Go. On a --dev-client stack, bun run start does the same.

You should see: your dev build connect and load the app; saving a file refreshes it as in Expo Go.

When to rebuild

Rebuild the dev build when something native changes: a module or library with native code, a config plugin, the name, bundle id, scheme, icon or splash. JavaScript changes never need a rebuild - they come from the dev server. When the app on the device and your tree disagree, the dev build usually tells you with a "native module not found" error.

If it doesn't work

  • "Project is incompatible with this version of Expo Go" or a missing native module - your stack needs a dev build. See A native module is missing in Expo Go.
  • bun run ios fails before compiling - xcode-select -p must point at Xcode (Starter and Pro: the "Xcode (dev build)" row of bun run doctor checks it), or ANDROID_HOME at your Android SDK for Android.
  • The iOS EAS build won't install - the device wasn't registered when the build ran. bunx eas-cli device:create, then build again.
  • The dev build opens but can't reach the dev server - phone and computer must be on the same network, or start with bunx expo start --dev-client --tunnel.
  • The build fails on credentials - see EAS build or credentials fail.

More in Troubleshooting.

Next

You can run every module you picked. Next, make the app yours: Make it yours.

On this page

Get ReadyNative