---
name: expo-app-builder
description: "Expo Router file-based nav, EAS Build, OTA updates, native modules — modern React Native without the YAML. Scaffolds Expo Router apps with EAS Build pipelines, OTA updates, and the dev-client config for native modules. Handles iOS + Android in one workflow."
license: MIT
---

# Expo App Builder (Router + EAS)

Scaffolds a production-shaped Expo app: file-based routing with Expo Router, EAS Build pipelines for iOS and Android, OTA delivery via EAS Update, and a dev client configured so you can pull in native modules without ejecting to bare React Native. Aimed at React Native developers who want one workflow that ships to both stores plus over-the-air patches, instead of hand-wiring Xcode schemes, Gradle variants, and update servers.

## When to use it

- Starting a new app and you want `app/`-directory routing, typed routes, and EAS wired from commit one.
- An existing Expo project that still builds locally but has no cloud build or OTA story.
- You need a native module (camera, BLE, a custom config plugin) and must move from Expo Go to a dev client.
- You want staging vs. production separated by EAS channels and build profiles.

## What it does

- Generates an Expo Router tree under `app/`: `_layout.tsx` roots, `(tabs)` groups, dynamic segments like `[id].tsx`, and enables `typedRoutes` in `app.json` for autocompleted `<Link href>` and `router.push`.
- Writes `eas.json` with `development`, `preview`, and `production` profiles, where `development` sets `developmentClient: true` and `distribution: internal`.
- Configures EAS Update: runtime version policy, `updates.url`, and channel-to-branch mapping so `production` builds pull from the `production` branch.
- Adds the `expo-dev-client` dependency and any config plugins a native module needs, so prebuild regenerates `ios/` and `android/` correctly.

## Usage

```bash
curl -fsSL --create-dirs -o ~/.claude/skills/expo-app-builder/SKILL.md https://claudeskil.com/skills/expo-app-builder/SKILL.md

# scaffold + first cloud builds
npx create-expo-app@latest my-app
eas build --profile development --platform all   # dev client for both OSes
eas build --profile production --platform all    # store-ready binaries

# ship a JS-only fix without a new binary
eas update --branch production --message "fix checkout crash"
```

```jsonc
// eas.json
{
  "build": {
    "development": { "developmentClient": true, "distribution": "internal" },
    "preview":     { "distribution": "internal", "channel": "preview" },
    "production":  { "channel": "production", "autoIncrement": true }
  }
}
```

## Tips & gotchas

- OTA updates only patch JS and assets. Adding or upgrading a native module requires a fresh `eas build` — bump `runtimeVersion` so old binaries don't pull incompatible bundles.
- The dev client is not Expo Go. After installing a native module, rebuild the dev client; reloading JS alone won't include the native code.
- Channels (build-time) and branches (where updates live) are mapped via `eas channel`. Pointing a channel at the wrong branch is the most common "my update didn't show up" cause.
- Run `npx expo-doctor` before a release build to catch config-plugin and dependency mismatches early.

## FAQ

**Do I have to eject to use native modules?** No. The dev client plus config plugins keeps you in the managed-ish workflow; `expo prebuild` regenerates native dirs on demand.

**Can I self-host updates instead of EAS?** Yes — point `updates.url` at any expo-updates–compatible endpoint, though EAS Update is the default path here.

**iOS and Android in one command?** Yes: `--platform all` builds both; channels and runtime versions are shared across platforms.
