Expo Application Services (EAS) deployment pattern library for React Native and Expo apps — EAS Build for iOS and Android native builds in the cloud, EAS Submit for App Store Connect and Google Play Console uploads, EAS Update for OTA updates without app store review (shipping JavaScript fixes in hours instead of days), eas.json build profiles (development / preview / production), credentials management (Apple certificates, provisioning profiles, keystores), environment variables per profile, build caches, internal distribution via Ad-Hoc or TestFlight Internal Testing, monorepo support with workspaces, and integration with CI (GitHub Actions). Use when building or deploying a React Native / Expo app to iOS or Android, configuring build profiles, managing signing credentials, pushing OTA updates, or automating mobile deployment via CI. Differentiates from platform-specific skills (deploy-app-store, deploy-play-store) by covering the build pipeline, not the store submission workflow.
EAS est la suite Expo pour builder, tester, et distribuer des apps React Native sans devoir configurer Xcode/Android Studio localement. Trois services clés : EAS Build, EAS Submit, EAS Update.
# Install EAS CLI
npm install -g eas-cli
# Login
eas login
# Configurer un projet
cd my-app
eas build:configure
# Génère eas.json et ajoute projectId dans app.json
eas.json — profiles de build{
"cli": {
"version": ">= 14.0.0",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"channel": "development",
"env": {
"API_URL": "https://dev.example.com"
}
},
"preview": {
"distribution": "internal",
"channel": "preview",
"ios": {
"simulator": true
},
"env": {
"API_URL": "https://staging.example.com"
}
},
"production": {
"channel": "production",
"autoIncrement": true,
"env": {
"API_URL": "https://api.example.com"
}
}
},
"submit": {
"production": {
"ios": {
"appleId": "[email protected]",
"ascAppId": "1234567890",
"appleTeamId": "ABCD1234EF"
},
"android": {
"serviceAccountKeyPath": "./pc-api-xxx.json",
"track": "production",
"releaseStatus": "completed"
}
}
}
}
# Build preview pour TestFlight Internal
eas build --profile preview --platform ios
# Build production pour soumission App Store
eas build --profile production --platform ios
# Build Android APK pour test interne
eas build --profile preview --platform android
# Build Android AAB pour Play Store
eas build --profile production --platform android
eas build --profile preview --platform ios --local # ou sur EAS si tu veux
Les builds iOS simulator ne nécessitent pas de certificats Apple — utile pour du test rapide.
# Laisser EAS gérer les certificats
eas credentials
# → iOS → Set up a new build credential
EAS peut :
Ou bien uploader manuellement les credentials existants.
eas credentials
# → Android → Set up a new build credential
Règle critique : le keystore Android doit être sauvegardé off-site. Si perdu, impossible de publier une update.
# Submit à App Store Connect (TestFlight → Review → App Store)
eas submit --profile production --platform ios --latest
# Submit à Play Console
eas submit --profile production --platform android --latest
Prérequis iOS :
ascAppId dans eas.jsonPrérequis Android :
# Publier une update JS/assets sans rebuild
eas update --branch production --message "Fix login bug"
Les users reçoivent la update au prochain lancement de l'app (ou via Updates.checkForUpdateAsync() en code).
Limites :
runtimeVersion)// app.json
{
"expo": {
"runtimeVersion": {
"policy": "appVersion"
}
}
}
appVersion policy : chaque version native est sa propre "runtime". Les updates OTA ne vont que vers les users sur la même version native.
EAS injecte les variables déclarées dans eas.json au moment du build. Pour les secrets :
# Secret côté EAS (chiffré)
eas secret:create --scope project --name STRIPE_KEY --value sk_live_xxx
# Le build l'injecte comme env var
Dans le code :
const STRIPE_KEY = process.env.EXPO_PUBLIC_STRIPE_KEY // accessible côté JS runtime si préfixé EXPO_PUBLIC_
Règle : les vars préfixées EXPO_PUBLIC_ sont accessibles dans le JS bundle (donc visible par les users). Les vars sans préfixe sont server-side only (build-time).
// eas.json dans un monorepo pnpm
{
"build": {
"production": {
"node": "20.0.0",
"pnpm": "9.0.0",
"prebuildCommand": "pnpm --filter=@app/mobile install"
}
}
}
Aussi possible via cli.requireCommit: true pour forcer un commit avant chaque build (évite les builds avec du working dir sale).
# .github/workflows/eas-build.yml