Repack job use cases
The repack job is suitable for reducing CI build times by reusing existing builds, triggering full native builds when required, and delivering faster feedback loops to teams. The repack job is not suitable for production builds that require going through the complete pipeline for correct symbolication and app signing.
Maestro screen recording performance impact
Recording screen in Maestro may impact emulator performance. When using record_screen: true, you may want to use large runners (specified via runs_on: linux-large-nested-virtualization) to ensure adequate computing resources.
Android system image package selection for Maestro
When specifying android_system_image_package for Maestro tests, run `sdkmanager --list` on your machine to list available packages and choose an x86_64 variant. Examples of valid packages: system-images;android-36;google_apis;x86_64 and system-images;android-35-ext15;google_apis_playstore;x86_64. Newer images require more computing resources, for which you may want to use large runners.
Maestro Cloud API key requirement
For the maestro-cloud job, you must either set the maestro_api_key parameter or the MAESTRO_CLOUD_API_KEY environment variable. Go to Settings on Maestro Cloud (app.maestro.dev) to generate an API key, then add it to your project's Environment variables on expo.dev.
Maestro flow asset storage
Maestro commands such as takeScreenshot and startRecording save assets with relative paths that will be available within the 'Maestro Test Results' artifact in the Artifacts section. These can be used for debugging later.
iOS device availability differs across runner images
iOS device availability for Maestro testing differs across runner images. A list of available devices can be found in the job logs when configuring device_identifier for iOS.
EAS Workflows cannot share entire job or workflow configurations
You cannot currently share an entire job or workflow configuration across files. Custom functions only let you reuse sequences of custom steps in jobs or hooks, but full workflow or job configurations cannot be shared.
EAS Workflows does not support matrix builds
Matrix builds are not currently supported in EAS Workflows. This means you cannot run multiple variations of the same workflow in parallel with different configurations.
Workflow file must be in .eas/workflows directory
The workflow file must be located inside the .eas/workflows directory. For push and pull_request events, the file must exist on the triggering branch. For schedule and ref_delete events, EAS reads the workflow file from the repository's default branch.
GitHub connection required for GitHub event triggers
Triggers such as push, pull_request, and ref_delete require the EAS project to be linked to a GitHub repository.
env key not available on certain job types
The env key is not available on the following job types: apple-device-registration-request, branch-delete, doc, get-build, github-comment, require-approval, and slack.
Scheduled workflows run only from default branch in GMT
on.schedule workflows only run from the repository's default branch, run in the GMT time zone, and may be delayed during periods of high load.
Trigger filters must match events
Trigger filters such as branches, tags, paths, types, and labels must match the event. For example, on.push.branches: ['main'] ignores pushes to every other branch.
Workflow triggers skipped with commit message markers
Runs triggered by push and pull_request events are skipped when the commit message contains [eas skip], [skip eas], or [no eas].
Validate workflow YAML syntax and schema
Use the command `eas workflow:validate .eas/workflows/my-workflow.yml` to check a workflow file for YAML syntax and schema errors before running it. The command also validates any custom functions that the workflow calls from its steps or hooks.
on.app_store_connect.app_version states
Supported app_version states for filtering: accepted, developer_rejected, in_review, invalid_binary, metadata_rejected, pending_apple_release, pending_developer_release, prepare_for_submission, processing_for_distribution, ready_for_distribution, ready_for_review, rejected, replaced_with_new_version, waiting_for_export_compliance, waiting_for_review. Defaults to all supported states when not provided.
on.app_store_connect.build_upload states
Supported build_upload states for filtering: complete, failed, processing, awaiting_upload. Defaults to all supported states when not provided.
on.app_store_connect.external_beta states
Supported external_beta states for filtering: processing, processing_exception, missing_export_compliance, ready_for_beta_testing, in_beta_testing, expired, ready_for_beta_submission, in_export_compliance_review, waiting_for_beta_review, in_beta_review, beta_rejected, beta_approved. Defaults to all supported states when not provided.
on.app_store_connect.beta_feedback types
Supported beta_feedback types for filtering: crash, screenshot. Defaults to all supported types when not provided. All filter values must be lowercase and are case-sensitive.
on.schedule.cron trigger
The on.schedule.cron trigger runs workflows on a schedule using unix-cron syntax. Scheduled workflows run only on the default branch. Scheduled workflows may be delayed during high load periods and in rare cases may be skipped or run multiple times—workflows should be idempotent. A workflow can have multiple cron schedules. Scheduled workflows run in GMT time zone.
submit pre-packaged job type
The submit job submits builds to app stores using EAS Submit. Parameters: build_id (string, required), profile (string, optional, default: production), groups (string[], optional). Outputs: apple_app_id, ios_bundle_identifier, android_package_id.
on.workflow_dispatch.inputs configuration
The on.workflow_dispatch.inputs defines inputs for manual workflow triggering via eas workflow:run command. Each input has: type (required, can be string, boolean, number, choice, or environment), description (optional), required (optional, defaults to false), default (optional, must match input type), and options (required for type: choice, contains array of strings). Inputs are available in workflow jobs using ${{ inputs.<input_name> }} syntax.
Providing workflow dispatch inputs
When running a workflow with inputs, you can provide them three ways: 1) Command-line flags using -F flag (e.g., -F environment=production -F debug=true), 2) JSON via stdin (e.g., echo '{"environment": "production"}' | eas workflow:run), 3) Interactive prompts if required inputs are missing and not using --non-interactive.
Workflow jobs structure
A workflow run is made up of one or more jobs. Each job must have a unique ID containing alphanumeric characters and underscores.
jobs.<job_id>.name property
The name property provides a human-friendly name for the job displayed on the workflow's detail page.
jobs.<job_id>.environment values
The environment property sets the EAS environment variable environment for the job. Possible values are: production, preview, or development. When omitted, the default depends on job type: build jobs infer from the build profile's environment in eas.json, submit jobs inherit from the submitted build, maestro and maestro-cloud jobs default to preview, all other jobs default to production.
jobs.<job_id>.env environment variables
The env property sets environment variables for the job. Available on all jobs running a VM (all jobs except: apple-device-registration-request, branch-delete, doc, get-build, github-comment, require-approval, slack, and update-rollout). Supports interpolation with ${{ }} syntax, including references to outputs from previous jobs.
jobs.<job_id>.hooks property
Hooks run additional steps before or after main job actions. Supported on: build, deploy, fingerprint, maestro, maestro-cloud, repack, submit, testflight, and update jobs. Hook names are job-specific. Use defaults.hooks to set default hooks for all jobs. Hook steps can call custom functions like job steps.
jobs.<job_id>.defaults.run.working_directory
Sets the directory to run commands in for all steps in the job. The path is relative to the app's base directory.
defaults.hooks configuration
Default hooks for all jobs in the workflow. Each job runs applicable hook keys and ignores others. A job-level hook key overrides the same key from defaults.hooks. To opt a single job out of a default hook, set the key to an empty array.
defaults.image for VM image
Sets default VM image to use for all jobs in the workflow. Using an sdk-XX image tag is recommended. See Infrastructure documentation for available images. Individual jobs can override with jobs.<job_id>.image.
defaults.tools configuration
Specifies versions of tools for workflow jobs. Available tools: node (via nvm), yarn (via npm -g), corepack (boolean, defaults to false), pnpm (via npm -g), bun (via install script), ndk (Android NDK via sdkmanager), bundler (via gem install -v), fastlane (via gem install -v), cocoapods (via gem install -v).
concurrency configuration
The concurrency property controls concurrency for same-branch workflows. It supports cancel_in_progress (true to cancel current in-progress runs when new run starts from GitHub) and group (currently must use placeholder value ${{ workflow.filename }}-${{ github.ref }}).
jobs.<job_id>.needs for job dependencies
The needs property is a list of job IDs whose jobs must complete successfully before this job will run. Creates a sequential dependency chain.
jobs.<job_id>.after for job completion
The after property is a list of job IDs that must complete (successfully or not) before this job will run. Unlike needs, this allows downstream jobs to run regardless of upstream job success/failure.
jobs.<job_id>.if conditional execution
The if property determines whether a job should run based on a condition using ${{ }} syntax. When true, the job runs; when false, it's skipped. Skipped jobs won't have completed successfully and downstream jobs in their needs list won't run.
Workflow interpolation syntax
Use ${{ expression }} syntax to access context properties and functions in workflows. Examples: ${{ github.ref_name }}, ${{ needs.build_ios.outputs.build_id }}, ${{ inputs.name }}.
after context in workflows
The after context provides a record of all upstream jobs in the current job's after list. Each job provides: status ('success', 'failure', 'skipped') and outputs (job-specific).
needs context in workflows
The needs context provides a record of all upstream jobs in the current job's needs list. Each job provides: status ('success', 'failure', 'skipped') and outputs (job-specific). Most pre-packaged jobs expose specific outputs.
steps context in workflows
The steps context is a record of all steps in the current job. Each step provides outputs set using the set-output function. Available only within a job's steps, not at workflow level. To expose a step's output to other jobs, use set-output and the job's outputs configuration.
github context in workflows
The github context contains: triggering_actor, event_name (pull_request, push, schedule, workflow_dispatch), sha, ref (e.g. refs/heads/main), ref_name (e.g. main), ref_type (branch, tag, other), commit_message (push/schedule only), label, repository, repository_owner, and event (full GitHub webhook payload). If triggered from eas workflow:run, event_name is workflow_dispatch and other properties are empty.
workflow context properties
The workflow context provides: id (workflow ID), name (workflow name), filename (filename of the workflow), url (URL to workflow).
app_store_connect context
The app_store_connect context contains information about App Store Connect entities. Available only for workflows triggered by App Store Connect events. Contains: app (id), build_upload (id, state, cf_bundle_version, cf_bundle_short_version_string, platform, uploaded_date, created_date, build.id), app_version (id, state), external_beta (id, state), beta_feedback (id, type, url).
env context in workflows
The env context is a record of environment variables available in the current job context. Available only within a job's context, not at the workflow level.
success() function in workflows
The success() function returns whether all previous jobs have succeeded. Used in conditionals with the if property.
failure() function in workflows
The failure() function returns whether any previous job has failed. Used in conditionals with the if property.
fromJSON() function in workflows
The fromJSON(value) function parses a JSON string, equivalent to JSON.parse().
toJSON() function in workflows
The toJSON(value) function converts a value to a JSON string, equivalent to JSON.stringify().
contains() function in workflows
The contains(value, substring) function checks whether value contains substring.
startsWith() function in workflows
The startsWith(value, prefix) function checks whether value starts with prefix.
endsWith() function in workflows
The endsWith(value, suffix) function checks whether value ends with suffix.
hashFiles() function in workflows
The hashFiles(...globs) function returns a hash of files matching the provided glob patterns. Useful for cache keys. Available only within a job's steps, not at the workflow level.
replaceAll() function in workflows
The replaceAll(input, stringToReplace, replacementString) function replaces all occurrences of stringToReplace in input with replacementString.
substring() function in workflows
The substring(input, start, end) function extracts a substring from input starting at start and ending at end. If end is not provided, extracts from start to the end of input. Uses String#substring under the hood.
build pre-packaged job type
The build job creates an Android or iOS build using EAS Build. Parameters: platform (ios | android, required), profile (string, optional, default: production), message (string, optional), refresh_ad_hoc_provisioning_profile (boolean, optional). Outputs: build_id, app_build_version, app_identifier, app_version, channel, distribution, fingerprint_hash, git_commit_hash, platform, profile, runtime_version, sdk_version, simulator.
deploy pre-packaged job type
The deploy job deploys using EAS Hosting. Parameters: alias (string, optional), prod (boolean, optional), source_maps (boolean, optional). Outputs: deploy_json, deploy_url, deploy_alias_url, deploy_deployment_url, deploy_identifier, deploy_dashboard_url.
fingerprint pre-packaged job type
The fingerprint job calculates a fingerprint of the project. Parameter: environment (production, required, should match build profile). Outputs: android_fingerprint_hash, ios_fingerprint_hash. For accurate fingerprint matching, ensure the fingerprint job's environment matches build profile.
get-build pre-packaged job type
The get-build job retrieves an existing build from EAS. Parameters: platform (ios | android, optional), profile (string, optional), distribution (store | internal | simulator, optional), channel (string, optional), app_identifier (string, optional), app_build_version (string, optional), app_version (string, optional), git_commit_hash (string, optional), fingerprint_hash (string, optional), sdk_version (string, optional), runtime_version (string, optional), simulator (boolean, optional), wait_for_in_progress (boolean, optional). Outputs same as build job.
testflight pre-packaged job type
The testflight job distributes iOS builds to TestFlight. Requires exactly one of: build_id (upload and submit to TestFlight) or asc_build_id (submit already uploaded build). Parameters: build_id (string, mutually exclusive with asc_build_id), profile (string, optional, default: production, only with build_id), wait_processing_timeout_seconds (number, optional, default: 1800), asc_build_id (string, mutually exclusive with build_id), internal_groups (string[], optional), external_groups (string[], optional), changelog (string, optional), submit_beta_review (boolean, optional). Outputs: apple_app_id, ios_bundle_identifier, asc_build_id (only when submitting already uploaded build).
update pre-packaged job type
The update job publishes using EAS Update. Parameters: message (string, optional), platform (string, optional, android | ios | all, defaults to all), branch (string, optional), channel (string, optional, cannot be used with branch), rollout_percentage (number, optional, 0-100, defaults to 100), private_key_path (string, optional), upload_sentry_sourcemaps (boolean, optional, defaults to try without failing). Outputs: first_update_group_id, updates_json (stringified JSON array).