This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Lerna-based monorepo containing the EAS CLI and all supporting build libraries.
-
packages/eas-cli - The main CLI tool (published as
eas-cli)- 95+ commands organized by domain (build, submit, update, channel, credentials, etc.)
- Built on oclif (Open CLI Framework)
- Entry point:
packages/eas-cli/bin/run
-
packages/eas-json - EAS configuration parser (published as
@expo/eas-json)- Validates
eas.jsonconfiguration files using Joi schemas - Manages build, submit, and deploy profiles
- Supports JSON5 via golden-fleece
- Validates
-
packages/eas-build-cache-provider - Build cache plugin (published as
eas-build-cache-provider)- Optimizes build caching for Expo CLI
-
packages/eas-build-job - Build job definitions (published as
@expo/eas-build-job)- Defines all data structures for build operations (Job, BuildPhase, BuildMode, Platform, Workflow)
- Provides type definitions and validation schemas (Zod, Joi)
- Contains BuildPhase enum that defines the traditional build pipeline stages
- Key exports:
Job,BuildPhase,BuildMode,BuildTrigger,Workflow,ArchiveSource - Foundation that all other build packages depend on
-
packages/build-tools - Build execution engine (published as
@expo/build-tools)- Orchestrates all build operations through
BuildContext<T extends Job> - Contains platform-specific builders:
androidBuilder(),iosBuilder(),runCustomBuildAsync() - Manages build phases, artifact uploading, caching, credentials
- Provides functions for custom builds
- Integrates with GraphQL API
- Orchestrates all build operations through
-
packages/steps - Custom build workflow engine (published as
@expo/steps)- Framework for defining and executing custom build steps
- Key abstractions:
BuildWorkflow: Orchestrates sequential step executionBuildStep: Individual executable unit with inputs/outputsBuildStepGlobalContext: Manages shared state and interpolationBuildStepContext: Per-step execution context
- Supports conditional execution with
ifexpressions (using jsep) - Template interpolation:
${{ steps.step-id.outputs.outputName }} - Parses build configs from YAML/JSON
-
packages/local-build-plugin - Local build execution (published as
eas-cli-local-build-plugin)- Allows running EAS builds locally on developer machines
- Entry point:
packages/local-build-plugin/src/main.ts - Sets
EAS_BUILD_RUNNER=local-build-pluginenvironment variable - Reuses all build-tools logic for consistency with cloud builds
-
packages/worker - Turtle Worker service (private, not published)
- Runs on EAS build VMs/pods
- WebSocket server for communication with Turtle Launcher
- Wraps
@expo/build-toolsto execute actual React Native builds
-
packages/logger - Bunyan-based structured logging (published as
@expo/logger)- Used by all build packages
-
packages/downloader - HTTP file downloading with retry logic (published as
@expo/downloader) -
packages/turtle-spawn - Child process spawning with error handling (published as
@expo/turtle-spawn) -
packages/template-file - Lodash-based template string interpolation (published as
@expo/template-file) -
packages/create-eas-build-function - CLI scaffolding tool for custom build functions (published as
create-eas-build-function) -
packages/expo-cocoapods-proxy - Ruby gem for CocoaPods proxy (published as
expo-cocoapods-proxygem)
Note: Some packages have their own CLAUDE.md with package-specific guidance. Click the links above to view them.
yarn install # Install all dependencies
yarn build # Build all packages in the monorepoyarn start # Watch mode with parallel builds across all packages
yarn watch # Alias for start
# Development with relaxed TypeScript rules (allows unused variables)
yarn start-allow-unusedyarn run -T lerna run test # Run all tests across packages
yarn run -T lerna run test -- --watch # Watch mode across packages (heavier)
#
# If you use `yarn test`, remember to pass args through two separators:
# yarn test -- -- --watch
# Run tests for a specific package
cd packages/eas-cli && yarn test
cd packages/eas-json && yarn test
cd packages/worker && yarn test
cd packages/build-tools && yarn test
cd packages/steps && yarn testyarn typecheck # TypeScript type check all packages
yarn lint # Oxlint across all packages
yarn fmt:check # Oxfmt format check# From repository root:
yarn eas <command> # Run via root package script
# Or use the binary directly:
packages/eas-cli/bin/run <command>
# Recommended: Create an alias for development
alias easd="$(pwd)/packages/eas-cli/bin/run"
easd build --helpSet up environment variables for testing local builds:
export EAS_LOCAL_BUILD_PLUGIN_PATH=$HOME/expo/eas-cli/bin/eas-cli-local-build-plugin
export EAS_LOCAL_BUILD_WORKINGDIR=$HOME/expo/eas-build-workingdir
export EAS_LOCAL_BUILD_SKIP_CLEANUP=1
export EAS_LOCAL_BUILD_ARTIFACTS_DIR=$HOME/expo/eas-build-workingdir/results
# Then run build with --local flag in eas-cli
eas build --localEach package has independent TypeScript compilation:
eas-cli:src/→build/eas-json:src/→build/eas-build-cache-provider:src/→build/worker:src/→dist/build-tools:src/→dist/eas-build-job:src/→dist/steps:src/→dist/(CommonJS only)local-build-plugin:src/→dist/- Other packages:
src/→dist/
TypeScript configs:
tsconfig.json- Base configuration (extends @tsconfig/node20)tsconfig.build.json- Production buildstsconfig.allowUnused.json- Development with relaxed rules
Most traditional build operations are wrapped in phases for tracking:
await ctx.runBuildPhase(BuildPhase.INSTALL_DEPENDENCIES, async () => {
// Phase logic here
});Phases can be marked as skipped, warning, or failed for granular reporting.
- BuildContext (
build-tools): For traditional builds, wraps Job, manages phases/artifacts/caching - CustomBuildContext (
build-tools): ImplementsExternalBuildContextProvider, bridges BuildContext to steps framework, used in custom builds and generic jobs - BuildStepGlobalContext (
steps): Manages step outputs, interpolation, shared state - BuildStepContext (
steps): Per-step context with working directory and logger
Steps are defined with:
id: Unique identifiername: Display namerun: Command or function referenceif: Optional condition (${{ always() }},${{ success() }}, etc.)inputs: Key-value inputs to the stepoutputs: Named outputs accessible to later steps
Built-in step functions are in packages/build-tools/src/steps/functions/
Uses jsep for expression evaluation:
if: ${{ steps.previous_step.outputs.success == 'true' && env.ENVIRONMENT == 'production' }}Artifacts tracked as ArtifactToUpload:
- Managed artifacts (APK, IPA, AAB) with specific handling
- Generic artifacts for any file
- Upload via
ctx.uploadArtifact()orupload-artifactstep
eas-cli → @expo/eas-json
→ @expo/build-tools → @expo/eas-build-job
→ @expo/steps → @expo/eas-build-job
→ @expo/logger
→ @expo/turtle-spawn
→ @expo/downloader
→ @expo/template-file
local-build-plugin → @expo/build-tools → @expo/eas-build-job
→ @expo/turtle-spawn
worker → @expo/build-tools
Most packages depend on @expo/eas-build-job as the source of truth for types.
- Framework: Jest with per-package configuration
- Shared base config:
jest/jest.shared.config.ts - Test locations:
__tests__/directories alongside source files - Mocking:
- File system:
memfs - HTTP:
nock - Utilities:
ts-mockito,mockdate
- File system:
Run a single test file:
cd packages/eas-cli && yarn test <path-to-test-file>
# Example:
cd packages/eas-cli && yarn test src/project/__tests__/projectUtils-test.ts- Create file in
packages/build-tools/src/steps/functions/yourFunction.ts - Export
createYourFunctionBuildFunction()following existing patterns - Add to
getEasFunctions()inpackages/build-tools/src/steps/functions/easFunctions.ts - Function receives
BuildStepContextand input/output maps
- Add pattern detection in
packages/build-tools/src/buildErrors/detectError.ts - Implement resolver for better error messages
- Helps users understand and fix build failures
- Android builder (
packages/build-tools/src/builders/android.ts): Gradle-based, handles APK/AAB generation, also seefunctionGroups/build.ts - iOS builder (
packages/build-tools/src/builders/ios.ts): Fastlane/Xcode-based, handles IPA generation, also seefunctionGroups/build.ts - Both use
runBuilderWithHooksAsync()which runs build result hooks (on-success, on-error, on-complete) from package.json
If you want to introduce breaking changes to the @expo/eas-build-job package, contact one of the CODEOWNERS to coordinate changes with EAS build servers and GraphQL API. Describe what changes you want to make and why. After everything is deployed to production, you can introduce a PR that relies on the new implementation.
# API Configuration
export EXPO_STAGING=1 # Use staging API (https://staging-api.expo.dev)
export EXPO_LOCAL=1 # Use local API (http://127.0.0.1:3000)
# Development
export EAS_NO_VCS=1 # Disable version control checks
export EXPO_DEBUG=1 # Enable debug loggingAll changes should be validated before committing. At minimum run package-level tests (e.g. jest-unit)
for touched code, then run type checks/linting and format the repo:
yarn fmt # Apply Oxfmt formatting
yarn typecheck # Validate TypeScript types
yarn lint # Run Oxlint
yarn fmt:check # Run Oxfmt format checkUse the Log module from @expo/logger:
import { Log } from '@expo/logger';
Log.log('Info message');
Log.warn('Warning message');
Log.error('Error message');When creating pull requests, make sure to adhere to PULL_REQUEST_TEMPLATE.
- When possible, prepend commit messages with
[PACKAGE-BEING-CHANGED], e.g.[steps] Add new step function - Do not use prefixes like
chore:andfeat: - Commit messages should be concise. Only complex changes should be longer than one line
- Commit changes in logical groups
- Update
CHANGELOG.mdin the appropriate package - Version bump is automated based on changelog:
- Breaking changes → MAJOR
- New features → MINOR
- Otherwise → PATCH
- GitHub Actions workflow handles release automation
- Notifications sent to Slack #eas-cli channel
This repository contains packages under different licenses:
- MIT License:
eas-cli,@expo/eas-json,@expo/eas-build-job,eas-build-cache-provider - BUSL-1.1 (Business Source License):
@expo/build-tools,@expo/steps,@expo/logger,@expo/downloader,@expo/turtle-spawn,@expo/template-file,eas-cli-local-build-plugin
See LICENSE (MIT) and LICENSE-BUSL (BUSL-1.1) for details.
- Node Version: Requires Node.js (managed via Mise)
- Package Manager: Uses Yarn 4.12.0
- Compilation Target: CommonJS with Node resolution