# Run on a physical device (/docs/start/run-on-device)



Simulators cover most development, but push notifications, camera, haptics, deep links, and real performance need hardware. Both flows below produce **debug builds for testing only** — [store releases stay with Appbrew](/docs/ship/app-releases).

## Android [#android]

The easy one. Enable USB debugging on the phone, plug it in, and:

```bash
pnpm run-android
```

The runner uses whatever device `adb` already sees, sets up `adb reverse` so the phone reaches the dev server over USB, installs, and launches. Hot reload included. With an emulator also running, be explicit: `--device` forces a physical device (`--device=<serial>` picks one from `adb devices`), `--simulator` forces an emulator.

### A standalone debug APK [#a-standalone-debug-apk]

To hand a build to a teammate's device:

```bash
cd android && ./gradlew assembleDebug
# → android/app/build/outputs/apk/debug/app-debug.apk
```

Install it with `adb install -r <apk>`. One catch: **debug APKs don't embed the JS bundle** — the app expects a dev server. On the machine with the phone attached:

```bash
adb reverse tcp:8081 tcp:8081
pnpm start
```

Debug signing uses the keystore committed in the repo, so there is zero signing setup on Android.

## iOS [#ios]

`pnpm run-ios` is simulator-only by design. Physical iPhones go through Xcode:

<Steps>
  <Step>
    ### Install pods and open the workspace [#install-pods-and-open-the-workspace]

    ```bash
    pnpm pod-install
    open ios/<app>.xcworkspace
    ```

    Always the `.xcworkspace`, never the `.xcodeproj`.
  </Step>

  <Step>
    ### Set up development signing [#set-up-development-signing]

    Running on a device needs a **development signing profile**, and nothing more. In *Signing & Capabilities*, for the **Debug** configuration only, enable *Automatically manage signing* and select your development team; do the same for the notification-extension target. Xcode then provisions a development profile for your device automatically.

    <Callout type="warn" title="Development signing only">
      Don't create distribution certificates or provisioning profiles for the
      app, and leave the Release configuration untouched — distribution signing
      and store submission are managed by Appbrew. If your team can't sign the
      app's capabilities (push, associated domains), or you'd rather not touch
      signing at all, [contact Appbrew](/docs/start/getting-help) and we'll set
      up device builds for you.
    </Callout>
  </Step>

  <Step>
    ### Select your device and run [#select-your-device-and-run]

    Pick the connected iPhone as the destination (enable Developer Mode on the phone when iOS asks) and press Run with the Debug configuration. Debug device builds embed a JS bundle and also look for your dev server over Wi-Fi, so keep `pnpm start` running on the same network for hot reload.
  </Step>
</Steps>

<Callout type="info" title="Xcode can't find node?">
  Xcode builds run outside your shell. If the build fails resolving node,
  create `ios/.xcode.env.local` (git-ignored) with
  `export NODE_BINARY=<absolute path to node>` — `which node` tells you the
  path.
</Callout>

Build failures on either platform: [Troubleshooting](/docs/ship/troubleshooting).
