Acciones de GitHub + EAS
Una receta para conectar GitHub Actions a EAS Build, Submit y Update - cubriendo secretos, caché, disparadores de monorepo y expo-github-action.
Busca en todas las páginas de la documentación
Una receta para conectar GitHub Actions a EAS Build, Submit y Update - cubriendo secretos, caché, disparadores de monorepo y expo-github-action.
Tarjeta de referencia rápida - lista para copiar y pegar.
# .github/workflows/eas-build.yml
name: EAS Build
on:
workflow_dispatch:
push:
tags: ["v*"]
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- run: npm ci
- run: npm run typecheck && npm run test -- --ci
- run: eas build --profile production --platform all --non-interactive# Crear token robot (una vez, localmente)
npx eas-cli@latest login
# Panel de Expo → Access Tokens → Create token → pega en Secretos de GitHub como EXPO_TOKENCuándo usar esto:
v*) que no deben depender de una computadora portátil del desarrollador.apps/mobile debe activar flujos de trabajo móviles.Disposición del proyecto:
your-expo-app/
.github/workflows/
pr-checks.yml
eas-release.yml
eas.json
app.json
package-lock.json# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
branches: [main]
concurrency:
group: pr-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
quality:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npx expo customize tsconfig.json
- run: npm run format:check
- run: npm run lint
- run: npm run typecheck
- run: npm run test -- --ci --passWithNoTests# .github/workflows/eas-release.yml
name: EAS Release
on:
push:
tags: ["v*"]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
eas-cache: true
- run: npm ci
- run: npx expo-doctor
- run: npm run typecheck && npm run test -- --ci
- name: Build production
run: eas build --profile production --platform all --non-interactive --wait
- name: Submit iOS
run: eas submit --platform ios --latest --non-interactive
- name: Submit Android
run: eas submit --platform android --latest --non-interactive# .github/workflows/mobile-pr.yml
name: Mobile PR
on:
pull_request:
jobs:
changes:
runs-on: ubuntu-latest
outputs:
mobile: ${{ steps.filter.outputs.mobile }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
mobile:
- 'apps/mobile/**'
- 'packages/ui/**'
- 'packages/api-client/**'
- 'package-lock.json'
quality:
needs: changes
if: needs.changes.outputs.mobile == 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/mobile
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci
- run: npm run lint && npm run typecheck && npm run test -- --ci# Alternativa raíz de monorepo con Turborepo
npx turbo run lint typecheck test --filter=mobileLo que esto demuestra:
EXPO_TOKEN autentica eas build / submit sin login interactivo.eas-cache: true en expo-github-action acelera invocaciones CLI repetidas.npm ci + cache: npm restaura node_modules entre ejecuciones de flujo de trabajo.apps/web cambia.--non-interactive es obligatorio en CI - sin indicadores.| Secreto | Dónde | Usado para |
|---|---|---|
EXPO_TOKEN | Secretos de GitHub | eas build, submit, update, ejecuciones de flujo de trabajo |
NPM_TOKEN | Secretos de GitHub | Paquetes privados durante npm ci |
| Clave de API de App Store Connect | Credenciales de EAS | Envío de iOS - no duplicado en GitHub si usa EAS Submit |
| JSON de cuenta de servicio de Play | Credenciales de EAS | Envío de Android |
Crear EXPO_TOKEN desde un token de acceso de robot o CI de Expo - no el token personal de un desarrollador vinculado a sesiones de 2FA.
# Verifica el token localmente antes de agregarlo a GitHub
EXPO_TOKEN=xxx npx eas-cli@latest whoami| Entrada | Propósito |
|---|---|
eas-version | Pin CLI (latest o 16.x.x) |
token | Mapea a EXPO_TOKEN |
eas-cache | Caché descarga de EAS CLI entre trabajos |
packager | npm / yarn / pnpm - coincide con repo |
# npm - más simple
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
# Monorepo - apunta caché al archivo de bloqueo raíz
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: package-lock.json
# Caché remoto de Turborepo (opcional, repos más grandes)
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}npm ci siempre - no npm install - el archivo de bloqueo es el contrato| Patrón | Pros | Contras |
|---|---|---|
paths: en on.pull_request | GitHub nativo, cero deps | Grueso - pierde cambios de nombre de paquete compartido |
dorny/paths-filter | Salidas booleanas por trabajo | Dependencia de acción adicional |
turbo --filter=[origin/main...] | Solo afectados en repos grandes | Requiere configuración de gráfico de Turbo |
Ejecutar siempre raíz turbo run lint | Modelo mental simple | Más lento en PRs de solo docs |
Para etiquetas de lanzamiento, siempre compila desde la raíz del repo con npm ci completo - los filtros de ruta son optimizaciones solo para PR.
PR abierto - GitHub Actions (lint, tsc, test) - barato, cada push
Etiqueta empujada - EAS Workflow (build - Maestro - submit) - infra nativa, cadena cerradaquality de Actionstype: build / maestro / submit - EAS WorkflowsFalta EXPO_TOKEN - eas build se cuelga o solicita y falla. Arreglo: Secreto organizacional disponible para el flujo de trabajo; verifica con paso eas whoami.
npm install en CI - Instalaciones no deterministas; "pasa en CI, falla localmente". Arreglo: npm ci cuando existe package-lock.json.
Ejecutar envío con --latest después de que QA probó compilación anterior - La tienda obtiene binario no probado. Arreglo: Pasa --id <BUILD_ID> de la salida del paso de compilación.
El filtro de ruta ignora el archivo de bloqueo - La actualización de dependencia en raíz no activa verificaciones móviles. Arreglo: Incluye package-lock.json / pnpm-lock.yaml en rutas de filtro.
Contraseña de Apple ID en Secretos de GitHub - Se interrumpe en 2FA; antipatrón de seguridad. Arreglo: Credenciales gestionadas por EAS + clave de API de App Store Connect.
Sin concurrency en flujos de trabajo de PR - Seis ejecuciones en cola para envíos de corrección rápida. Arreglo: cancel-in-progress: true.
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| GitHub Actions + expo-github-action | Puertas PR + lanzamientos de etiquetas en GH | Quieres build-Maestro-submit solo en infra de EAS |
| Solo EAS Workflows | Casa YAML única en Expo | Necesitas ecosistema de acciones del mercado GH |
| Bitrise / CircleCI | Estándar empresarial ya pagado | Equipo de Expo greenfield - EAS es de menor ceremonia |
Local eas build | Emergencia de una sola vez | Tren de lanzamiento normal - no reproducible |
GitHub - Configuración - Secretos y variables - Acciones - EXPO_TOKEN. Para monorepos, secreto a nivel de organización compartido entre repos móviles.
Fija (16.4.0) para reproducibilidad; usa latest cuando quieras correcciones CLI automáticas. Alinea con eas-cli devDependency en package.json cuando sea posible.
on:
pull_request:
types: [labeled]
jobs:
preview:
if: contains(github.event.pull_request.labels.*.name, 'eas-preview')- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfileEstablece packager: pnpm en expo-github-action cuando sea aplicable.
Sí - pero tú gestionas el inicio del emulador, la instalación de APK y el caché. type: maestro de EAS Workflows es de menor ceremonia para equipos de Expo - Maestro E2E.
turbo run en CIVersiones de Stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última actualización: 16 jul 2026