dist/plugins/mobile-deployment-eas/skills/mobile-deployment-eas/SKILL.md
EAS Build, Update, Submit deployment patterns
npx skillsauth add agents-inc/skills mobile-deployment-easInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Quick Guide: EAS (Expo Application Services) handles cloud builds, OTA updates, and app store submission. Use build profiles in
eas.jsonto separate development/preview/production builds. Use EAS Update with runtime version fingerprinting for safe OTA deploys. Use--environmentflag (SDK 55+) instead of--channelwhen publishing updates. Let EAS manage credentials unless you have enterprise requirements.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use the --environment flag with eas update on SDK 55+ projects -- the --channel flag is replaced)
(You MUST set runtimeVersion with "fingerprint" policy for projects with native dependencies -- mismatched runtime versions crash apps on OTA update)
(You MUST use EAS Secrets for sensitive values -- NEVER put API keys or tokens in eas.json env blocks or EXPO_PUBLIC_ variables)
(You MUST run eas build from the app directory in monorepos -- NOT from the repository root)
</critical_requirements>
Auto-detection: EAS Build, EAS Update, EAS Submit, eas.json, eas build, eas update, eas submit, eas credentials, eas secret, EAS Workflows, build profiles, OTA updates, runtime version, fingerprint policy, app store submission, code signing, eas-cli
When to use:
Key patterns covered:
eas.json build profiles with inheritance (extends)autoIncrement and appVersionSourceWhen NOT to use:
npx expo run:ios/android without EASEAS separates building, updating, and submitting into distinct services that compose into a deployment pipeline. The key insight is that most mobile deployment complexity lives in credentials, versioning, and environment management -- EAS automates all three.
Core principles:
eas.json, not as CLI arguments scattered across scriptsMental model:
eas.json is your deployment configuration hub. Build profiles define HOW to build (development client, APK vs AAB, simulator vs device). Channels define WHERE updates go. Runtime versions define WHAT is compatible. Secrets define access to external services during builds.
Use extends to share configuration between profiles. Define a base profile for shared settings, then extend for each environment.
{
"build": {
"base": {
"node": "20.17.0",
"env": { "EXPO_PUBLIC_APP_ENV": "development" }
},
"development": {
"extends": "base",
"developmentClient": true,
"distribution": "internal",
"ios": { "simulator": true },
"android": { "buildType": "apk" }
},
"production": {
"extends": "base",
"autoIncrement": "buildNumber",
"channel": "production",
"env": { "EXPO_PUBLIC_APP_ENV": "production" }
}
}
}
Why good: extends eliminates duplication across profiles, autoIncrement handles version bumps automatically, environment-specific env vars prevent mixing configurations
Full profile examples with all options: examples/core.md - Build Profiles section
Runtime version determines which builds are compatible with which OTA updates. The "fingerprint" policy auto-detects native changes.
// app.config.ts
export default {
runtimeVersion: {
policy: "fingerprint", // Auto-detects native code changes
},
updates: {
url: `https://u.expo.dev/${process.env.EAS_PROJECT_ID}`,
},
};
| Policy | Behavior | Best For |
| ------------- | ----------------------------------------- | -------------------------------- |
| fingerprint | Hashes all native dependencies | Complex apps with native modules |
| appVersion | Uses version from app config | Simple apps, manual control |
| Custom string | Exact match (e.g., "1.0.0") | Full manual control |
Gotcha: fingerprint can be aggressive -- it may flag changes that don't actually affect native code, requiring more builds than necessary. Use appVersion for simpler projects.
Full configuration examples: examples/core.md - Runtime Versions section
Updates go to a channel, which points to a branch. Builds pull updates from their assigned channel.
# SDK 55+ uses --environment (REQUIRED)
eas update --environment production --message "Fix login crash"
# SDK 54 and earlier uses --channel
eas update --channel production --message "Fix login crash"
Channel-branch relationship: By default, a channel auto-links to a branch with the same name. You can reassign: eas channel:edit production --branch hotfix-v2.
Rollback: If a bad update ships, roll back immediately:
eas update:rollback --channel production
Full update workflow with client-side hook: examples/updates.md
EAS Submit handles both iOS App Store and Google Play submission. Use --auto-submit to chain build and submit.
# Submit latest build
eas submit --platform ios
eas submit --platform android
# Build and submit in one step
eas build --profile production --platform ios --auto-submit
# Submit a specific build by ID
eas submit --platform ios --id [build-id]
{
"submit": {
"production": {
"ios": {
"appleId": "[email protected]",
"ascAppId": "1234567890",
"appleTeamId": "ABC123DEF"
},
"android": {
"serviceAccountKeyPath": "./google-services.json",
"track": "internal",
"releaseStatus": "draft"
}
}
}
}
Why good: track: "internal" starts with internal testing before promoting, releaseStatus: "draft" gives manual control over publishing in Play Console
Full submission configuration: examples/core.md - Submit Configuration section
Let EAS manage credentials by default. Use eas credentials to inspect or override.
# Interactive credential management
eas credentials --platform ios
eas credentials --platform android
# Register iOS test devices for internal distribution
eas device:create
eas device:list
Automatic management (recommended): EAS creates Distribution Certificates, Provisioning Profiles (iOS), and keystores (Android) automatically on first build. Teammates with EAS access can build without Apple Developer credentials.
Local credentials (enterprise): Use credentials.json at the app root with paths to your own signing files. Set "credentialsSource": "local" in the build profile.
Full credentials patterns: examples/credentials.md
Store sensitive build-time values server-side. Secrets are injected as environment variables during builds.
# Project-scoped secret
eas secret:create --scope project --name MY_AUTH_TOKEN --value "your-token"
# Account-scoped secret (shared across projects)
eas secret:create --scope account --name GOOGLE_SERVICES_JSON --type file --value ./google-services.json
# List and manage
eas secret:list
eas secret:delete --name MY_AUTH_TOKEN
Secrets are available as environment variables in the build process -- no eas.json configuration needed.
Key distinction: EXPO_PUBLIC_* variables are embedded in the JS bundle (visible to users). EAS Secrets are build-time only (never in the bundle).
Define complete CI/CD pipelines in .eas/workflows/*.yaml. Workflows orchestrate builds, tests, submissions, and notifications.
# .eas/workflows/deploy-production.yaml
name: Deploy Production
on:
push:
branches: [main]
jobs:
build_ios:
type: build
params:
platform: ios
profile: production
build_android:
type: build
params:
platform: android
profile: production
submit_ios:
needs: [build_ios]
type: submit
params:
platform: ios
submit_android:
needs: [build_android]
type: submit
params:
platform: android
Why good: Single YAML defines the entire deployment pipeline, needs enforces job ordering, pre-packaged job types (build, submit) eliminate boilerplate
Full workflow examples with custom steps: examples/workflows.md
Run EAS CLI from the app directory, not the repo root. Each app has its own eas.json.
my-monorepo/
apps/
mobile/ <-- Run eas build from HERE
eas.json
app.config.ts
package.json
packages/
shared/
package.json <-- NOT from here
cd apps/mobile
eas build --profile preview --platform ios
Gotcha: EAS auto-detects your package manager (npm, pnpm, Yarn, Bun) and installs from the monorepo root. If detection fails with pnpm, ensure your pnpm-workspace.yaml is at the repo root.
</patterns>Full monorepo configuration: examples/core.md - Monorepo section
Detailed Resources:
<red_flags>
High Priority Issues:
--channel on SDK 55+ projects -- replaced by --environment flag; old flag no longer worksruntimeVersion in app config -- OTA updates fail silently or crash on incompatible buildseas.json env blocks -- config is committed to version control; use EAS Secrets insteadeas build from monorepo root -- must run from the app directory (apps/mobile/, not repo root)autoIncrement for production -- Android versionCode must strictly increase; Play Store rejects same or lower valuesMedium Priority Issues:
distribution: "store" for preview builds -- use "internal" for ad hoc/internal distributionresourceClass -- default may be slow for large projects; "medium" or "large" speeds up builds--non-interactive in CI -- EAS prompts for input by default; CI pipelines hang without this flag--auto-submit when build + submit are always paired -- saves a manual step and avoids submitting the wrong buildGotchas & Edge Cases:
fingerprint policy can be too aggressive -- may flag changes that don't affect native code, forcing unnecessary rebuildseas credentialsautoIncrement: "version" vs "buildNumber" -- "version" bumps the user-visible version string; "buildNumber" bumps the internal build number onlyappVersionSource: "remote" requires paid plan -- tracks versions server-side; free tier must manage locallybuildType: "apk" is for testing only -- Play Store requires "app-bundle" (AAB) for production submissionsextends depth limit is 5 levels -- circular dependencies cause build errorsdevelopment-device profile with "simulator": false</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md
(You MUST use the --environment flag with eas update on SDK 55+ projects -- the --channel flag is replaced)
(You MUST set runtimeVersion with "fingerprint" policy for projects with native dependencies -- mismatched runtime versions crash apps on OTA update)
(You MUST use EAS Secrets for sensitive values -- NEVER put API keys or tokens in eas.json env blocks or EXPO_PUBLIC_ variables)
(You MUST run eas build from the app directory in monorepos -- NOT from the repository root)
Failure to follow these rules will cause OTA update crashes, credential exposure, and build failures.
</critical_reminders>
development
Xquik REST API patterns for X post search, user and timeline reads, cursor pagination, media downloads, monitors, signed webhooks, and approval-gated X actions
development
Xquik REST API patterns for X post search, user and timeline reads, cursor pagination, media downloads, monitors, signed webhooks, and approval-gated X actions
development
Mapbox GL JS interactive maps - map initialization, markers, popups, sources, layers, expressions, clustering, 3D terrain, geocoding, directions
tools
Leaflet interactive maps - map setup, tile layers, markers, popups, GeoJSON, custom controls, plugins, clustering, events