> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tester.army/llms.txt
> Use this file to discover all available pages before exploring further.

# Dev Builds & Metro

> Why development builds of React Native and Expo apps can't run on TesterArmy's cloud devices, and how to build a release artifact that can.

React Native and Expo apps built in **development mode** do not embed their JavaScript bundle. Instead, they load it at runtime from a [Metro](https://metrobundler.dev/) dev server running on your machine. TesterArmy test devices run in the cloud and cannot reach your local Metro server, so a dev-mode app cannot start.

## How this failure looks

When a dev-mode build is uploaded, the app launches but immediately shows one of these screens instead of your app:

* A red error screen with **"No script URL provided"**
* **"Could not connect to development server"**
* **"Unable to load script. Make sure you're either running Metro..."**
* The **Expo dev launcher** asking for a development server URL

When the agent detects this, the run fails with the step error code `MOBILE_RELEASE_BUILD_REQUIRED` and links to this page.

## Why it happens

Development builds (`Debug` configuration on iOS, `debug` variant on Android, and Expo builds with `expo-dev-client` / `developmentClient: true`) expect a Metro dev server to serve the JavaScript bundle over the network. That works on your machine and simulator, but not on a remote test device.

TesterArmy needs a **self-contained build** with the JavaScript bundle embedded in the app binary.

## How to fix it

Build a release artifact and upload that instead.

<Tabs>
  <Tab title="iOS">
    Build a **Release** iOS Simulator app. For Expo / React Native projects, generate native files first if needed:

    ```bash theme={"theme":"vesper"}
    npx expo prebuild --platform ios

    xcodebuild -workspace ios/MyApp.xcworkspace \
      -scheme MyApp \
      -configuration Release \
      -sdk iphonesimulator \
      -destination 'generic/platform=iOS Simulator' \
      -derivedDataPath ios/build \
      build
    ```

    The `-configuration Release` flag is what embeds the JavaScript bundle. The simulator app bundle ends up under:

    ```bash theme={"theme":"vesper"}
    ios/build/Build/Products/Release-iphonesimulator/MyApp.app
    ```
  </Tab>

  <Tab title="Android">
    Build a **release** APK:

    ```bash theme={"theme":"vesper"}
    npx expo prebuild --platform android

    cd android
    ./gradlew assembleRelease
    ```

    <Warning>
      **Debug APKs usually require Metro**

      By default, React Native only bundles JavaScript into release variants. A
      `./gradlew assembleDebug` APK works only if your build embeds the bundle
      for debug builds too. When in doubt, upload the release APK.
    </Warning>

    Release builds must be signed. If you have not configured a release keystore, the default Expo prebuild setup signs release builds with the debug keystore, which is fine for testing.
  </Tab>
</Tabs>

## Expo EAS builds

If you build with EAS, make sure the build profile you upload from does **not** use a development client:

```json theme={"theme":"vesper"}
{
  "build": {
    "testerarmy-ios-simulator": {
      "ios": { "simulator": true }
    },
    "testerarmy-android-apk": {
      "android": { "buildType": "apk" }
    }
  }
}
```

Avoid `"developmentClient": true` in the profile used for TesterArmy uploads - it produces an `expo-dev-client` build that opens the dev launcher instead of your app.

See [Expo EAS](/mobile/expo-eas) for the full CI workflow.

## Verify before uploading

To check a build locally, install it on a simulator/emulator **without Metro running** (do not run `npx expo start` or `npm start`) and launch it. If the app opens normally, it is self-contained and ready to upload. See [App Uploads](/mobile/app-uploads) for upload instructions.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.