CI/CD Best Practices
A condensed summary of the 25 most important CI/CD practices for Expo SDK 57 mobile teams - drawn from every page in this section.
Search across all documentation pages
A condensed summary of the 25 most important CI/CD practices for Expo SDK 57 mobile teams - drawn from every page in this section.
Same scripts locally and in CI: npm run lint, typecheck, test, and format:check must work on a fresh clone - CI should not invoke one-off tool commands developers never run.
PR checks are fast gates: Lint, TypeScript, and Jest on every pull request - target under ten minutes; block merge via branch protection.
Release pipelines are separate: Tag-driven eas build and submit workflows - different triggers, different failure budget than PR checks - Mobile CI/CD Basics.
No laptop store builds: Production binaries come from EAS Build with credentials in EAS - not Xcode archives on one engineer's MacBook.
Same artifact CI to store: QA signs off on build_id; eas submit uses that ID - not --latest after a rebuild - Automated Store Promotion.
EXPO_TOKEN robot account: CI uses an Expo access token stored in GitHub Secrets - never personal passwords or interactive eas login - GitHub Actions + EAS.
npm ci in CI always: Lockfile-driven installs - npm install in workflows creates non-reproducible failures.
Node 20 LTS in CI: Align engines.node with GitHub Actions and EAS Workflows - matches SDK 57 tooling expectations.
Run npx expo customize before tsc: Typed routes need .expo/types on clean checkouts - CI Quality Gates.
Quality before type: build: EAS Workflows chain needs: [quality] so native compiles do not start on broken TypeScript - EAS Workflows.
Preview builds are label-gated: needs-preview label or path filters - not every typo spends EAS credits - Preview Builds on PRs.
Internal distribution for PR previews: distribution: internal + Android apk - QR install for QA on real devices - Internal Distribution.
Separate preview and production profiles: Preview must not touch production signing credentials or auto-increment store build numbers - Build Profiles & Flavors.
Maestro smoke gates submit: Two to four short flows on the production build_id before type: submit - Maestro E2E.
E2E stays thin; Jest stays wide: Critical paths in Maestro; branch coverage in unit tests - Mobile Testing Basics.
OTA only within runtimeVersion: eas update ships JS compatible with installed store binaries - Runtime Version Policy.
Native changes require store build: New Expo modules, config plugins, SDK bumps - never OTA alone - OTA Updates Basics.
Explicit update channels: production, staging, preview - no accidental cross-channel promotion - Release Channels & Branches.
Document OTA rollback: eas update --roll-back rehearsed before first production OTA - Rollback Runbook.
Release train calendar is shared: Mobile, backend, and QA see the same dependency checklist - API before breaking mobile, flags before visible features - Release Train Calendar.
Contract tests in PR checks: API shape drift caught before nightly - especially when backend deploys continuously - Contract Tests for APIs.
Nightlies catch integration drift: Scheduled full build on main when PR volume is high - alert, do not block merges.
Concurrency cancels stale PR runs: cancel-in-progress: true - save minutes and reduce confusing red checks on outdated commits.
Monorepo path filters or Turbo filter: Mobile CI skips when only unrelated packages change - but nightlies still validate full main.
Staged rollout after submit: Automated upload ≠ 100% users immediately - Play staged % and phased TestFlight - Staged Rollouts.
Both is common: GitHub for PR checks; EAS Workflows for build → Maestro → submit chains. Keep npm scripts identical.
PR checks (lint + tsc + test) + manual eas build on tag. Add preview-on-PR and automated submit as the app grows.
Native module, config plugin, navigation shell, or camera/permissions - yes. Copy and unit-test-only - no.
QA testing one binary and stores receiving another. Pin build_id end-to-end.
Yes - at least on release and nightly workflows. Catches dependency skew before expensive native builds.
Stack versions: This page was written for React 19.2.3, React Native 0.86.0, and Expo SDK 57 (
expo~57.0.4).
Reviewed by Chris St. John·Last updated Jul 16, 2026