Expo development workflow for {{project.name}} — Expo Go vs development builds, prebuild/CNG, running on simulators, emulators, and devices, and EAS Build/Submit/Update. Use when setting up, running, or shipping the app.
Installs into .claude/skills of the current project.
Are you the author of Expo App Dev?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/dustinkeeton-expo-app-dev)
---
name: expo-app-dev
description: Expo development workflow for {{project.name}} — Expo Go vs development builds, prebuild/CNG, running on simulators, emulators, and devices, and EAS Build/Submit/Update. Use when setting up, running, or shipping the app.
user-invocable: false
---
# Expo App Development Workflow
## App Configuration
Core identity lives in `app.json` (or `app.config.ts` when values must be computed):
```json
{
"expo": {
"name": "{{project.name}}",
"slug": "{{app.slug}}",
"scheme": "{{app.scheme}}",
"ios": { "bundleIdentifier": "{{app.iosBundleId}}" },
"android": { "package": "{{app.androidPackage}}" }
}
}
```
Use `app.config.ts` for dynamic values (env-dependent names, per-profile identifiers); it receives the static config and returns the final one.
## Expo Go vs Development Builds
| Client | When it works |
| --- | --- |
| Expo Go | Only while every dependency is inside the Expo SDK — no config plugins, no custom native modules |
| Development build | Everything else — any config plugin or native module means building your own dev client |
Decision rule: the moment the app needs anything outside the Expo SDK, switch to a development build. Build one locally with `npx expo run:ios` / `npx expo run:android`, or make a shareable/installable one with `eas build --profile development`.
## Continuous Native Generation (CNG / Prebuild)
`ios/` and `android/` are **build artifacts**, not source:
- Keep them gitignored; regenerate with `npx expo prebuild --clean`
- Never hand-edit the generated projects — changes are lost on the next prebuild
- Express native changes as config plugins in the app config instead
## Daily Dev Loop
- `npx expo start` — Metro dev server; press `i` for iOS simulator, `a` for Android emulator, scan the QR code for a physical device
- `npx expo start --clear` — reset the Metro cache when bundling behaves strangely
- Rebuild rule: JS and asset changes hot-reload via fast refresh; a new native dependency or an app-config/plugin change requires rebuilding the native app (`run:ios` / `run:android` or a new EAS build)
## EAS Basics
- `eas.json` defines build profiles — conventionally `development`, `preview`, `production`
- `eas build --platform ios|android|all --profile <name>` — cloud native builds
- `eas submit` — upload to App Store Connect / Google Play
- `eas update` — ship JS-only changes over the air to existing builds
- Runtime-version gating: an update only reaches builds whose runtime version matches. Any native change (new module, config plugin, SDK upgrade) bumps the runtime version and always means a new store build.
- CI authenticates with an `EAS_TOKEN` environment variable instead of interactive login
## Common Failure Modes
- **SDK mismatch**: the installed Expo Go only supports specific SDK versions — upgrade the app (`npx expo install --fix`) or use a development build
- **"Native module not found"** right after adding a dependency: the native app is stale — rebuild, don't just restart Metro
- **Weird bundling/transform errors**: stale Metro cache — `npx expo start --clear`
- **Prebuild drift**: someone hand-edited `ios/`/`android/` — port the change to a config plugin, then `npx expo prebuild --clean` to confirm nothing is lost