macOS & Linux CLI Best Practices
A condensed summary of 25 macOS and Linux CLI essentials for Expo SDK 57 teams - shared portable scripts, device tooling, and JSON automation drawn from every page in this section.
Search across all documentation pages
A condensed summary of 25 macOS and Linux CLI essentials for Expo SDK 57 teams - shared portable scripts, device tooling, and JSON automation drawn from every page in this section.
Check scripts into the repo: Put scripts/ci/ bash under version control - laptops, GitHub Actions, and EAS hooks run the same entrypoints, not one-off Slack snippets.
Use npx for Expo and EAS CLIs: npx expo-doctor and npx eas-cli@latest avoid global version drift between teammates and CI images.
Standardize on npm ci in automation: Lockfile-driven installs on CI; npm install only on local feature branches when intentionally updating deps.
Run npx expo-doctor before native work: Catches SDK 57 version skew before expo run:* or eas build waste twenty minutes on CocoaPods or Gradle.
Pair expo start --dev-client with dev builds: Custom native shells need the dev-client Metro flag - plain expo start targets Expo Go semantics.
Clear Metro with intent: npx expo start --clear after dependency upgrades; do not alias it to every save - it hides bundler bugs.
Reserve expo prebuild for native changes: Config plugins, entitlements, and new native modules - not every JS commit under CNG.
Mirror CI gates locally: npm run lint && npx tsc --noEmit && npm test -- --ci before eas build --non-interactive - same commands, same failure surface.
Export EXPO_TOKEN on CI only: Robot tokens in GitHub Secrets / EAS - never commit; verify with eas whoami in a dry-run job.
Parse eas build:list --json: Use jq for artifact URLs - human tables are not machine-readable and break when CLI formatting changes.
Fail closed with jq -er: Required JSON fields should exit non-zero when missing - prevents curl downloading HTML error pages as "APKs".
Use rg for log triage: Ripgrep JSONL and EAS logs with -g globs - faster than grep -R and respects .gitignore.
Resolve iOS simulator UDIDs in scripts: Device names collide across Xcode versions - xcrun simctl list devices available -j | jq is stable.
Boot simulators before simctl install: The booted alias targets nothing when Simulator is shut down - simctl boot then install.
Screenshot with simctl io for evidence: PNG artifacts for PRs, Maestro baselines, and App Store attachments - reproducible without Xcode UI.
Set ANDROID_HOME and JDK 17 explicitly: RN 0.86 Gradle expects JDK 17 - document paths in README and CI env blocks.
adb reverse tcp:8081 on USB Android: Physical devices do not reach laptop localhost without reverse - do this after every cable reconnect.
Suffix adb -s SERIAL with multiple devices: Emulator plus phone causes ambiguous target errors - enumerate with adb devices -l.
Filter logcat aggressively: '*:S' ReactNativeJS:V AndroidRuntime:E surfaces JS and fatal native errors without system spam.
Install APKs with adb install -r: Reinstall dev clients from EAS or assembleDebug without Android Studio - verify android.package matches.
Prefer LAN Metro; tunnel as fallback: --tunnel is slower - use USB adb reverse or shared Wi-Fi before defaulting to tunnel.
Chain commands with && in scripts: set -euo pipefail plus explicit gates - fail fast like CI, not silent partial success.
Store jq filters beside workflows: scripts/jq/latest-apk.jq reviewed in PRs - not inline one-liners duplicated across three YAML files.
Linux CI for Android; macOS for iOS simctl: Do not pretend simctl runs on ubuntu-latest - split jobs by platform capability.
Cross-read platform docs when CLI is not enough: Signing, entitlements, and Play tracks live in EAS Build, iOS Platform, and Android Platform - CLI clears dev friction, not store policy.
make ci or npm run ci:android).scripts/ are enough for most Expo teams; avoid macOS-only Makefile assumptions on Linux CI.shellcheck scripts/**/*.sh in PR checks when scripts grow past trivial.set -euo pipefail scripts portable between macOS bash and Linux dash-linked environments.adb, Metro, and EAS JSON tooling run on Linux fully.simctl and Xcode builds require macOS - use EAS cloud for iOS when Linux is the daily driver.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