Edit this page
Reference guide for the EAS Workflows configuration file syntax.
A workflow is a configurable automated process made up of one or more jobs. You must create a YAML file to define your workflow configuration.
To get started with workflows, see Get Started with EAS Workflows or see Examples for complete workflow configurations.
Workflow files use YAML syntax and must have either a .yml
or .yaml
file extension. If you're new to YAML and want to learn more, see Learn YAML in Y minutes.
Workflow files are located in the .eas/workflows directory in your project. The .eas directory should be at the same level as your eas.json file.
For example:
my-app
.eas
workflows
create-development-builds.yml
publish-preview-update.yml
deploy-to-production.yml
eas.json
name
The name of the workflow. This is displayed on the Expo dashboard on the workflows list page and is the title of the workflow's detail page.
name: My workflow
on
The on
key defines which GitHub events trigger the workflow. Any workflow can be triggered with the eas workflow:run
command, regardless of the on
key.
on:
# Trigger on pushes to main branch
push:
branches: ['main']
# And on pull requests starting with 'version-'
pull_request:
branches: ['version-*']
on.push
Runs your workflow when you push a commit to matching branches and/or tags.
With the branches
array, you can trigger the workflow only when those specified branches are pushed to. For example, if you use branches: ['main']
, only push to the main
branch will trigger the workflow. Supports globs.
With the tags
array, you can trigger the workflow only when those specified tags are pushed. For example, if you use tags: ['v1']
, only the v1
tag being pushed will trigger the workflow. Supports globs.
When neither branches
nor tags
are provided, branches
defaults to ['*']
and tags
defaults to []
, which means the workflow will trigger on push events to all branches and will not trigger on tag pushes. If only one of the two arrays is provided the other defaults to []
.
on:
push:
branches:
- 'main'
- 'feature/**'
# other branch names and globs
tags:
- 'v1'
- 'v2*'
# other tag names and globs
on.pull_request
Runs your workflow when a pull request event occurs on the matching branches.
With the branches
array, you can trigger the workflow only when those specified branches are the target of the pull request. For example, if you use branches: ['main']
, only pull requests to the main
branch will trigger the workflow. Supports globs. Defaults to ['*']
when not provided, which means the workflow will trigger on pull request events to all branches.
With the types
array, you can trigger the workflow only on the specified pull request event types. For example, if you use types: ['opened']
, only the pull_request.opened
event (sent when a pull request is first opened) will trigger the workflow. Defaults to ['opened', 'reopened', 'synchronize']
when not provided. Supported event types:
opened
reopened
synchronize
labeled
on:
pull_request:
branches:
- 'main'
- 'feature/**'
# other branch names and globs
types:
- 'opened'
# other event types
on.pull_request_labeled
Runs your workflow when a pull request is labeled with a matching label.
With the labels
array, you can specify which labels, when assigned to your pull request, will trigger the workflow. For example, if you use labels: ['Test']
, only labeling a pull request with the Test
label will trigger the workflow. Defaults to []
when not provided, which means no labels will trigger the workflow.
You can also provide the list of matching labels directly to on.pull_request_labeled
for simpler syntax.
on:
pull_request_labeled:
labels:
- 'Test'
- 'Preview'
# other labels
Alternatively:
on:
pull_request_labeled:
- 'Test'
- 'Preview'
# other labels
jobs
A workflow run is made up of one or more jobs.
jobs:
job_1:
# ...
job_2:
# ...
jobs.<job_id>
Each job must have an ID. The ID should be unique within the workflow and can contain alphanumeric characters and underscores. For example, my_job
in the following YAML:
jobs:
my_job:
# ...
jobs.<job_id>.name
The name of the job displayed on the workflow's detail page.
jobs:
my_job:
name: Build app
jobs.<job_id>.environment
The EAS environment variable environment to set for the job. There are three possible values:
production
(default)preview
development
The environment
key is available on all jobs except for the pre-packaged build
, submit
, and get-build
jobs.
jobs:
my_job:
environment: production | preview | development
jobs.<job_id>.defaults.run.working_directory
Sets the directory to run commands in for all steps in the job.
jobs:
my_job:
defaults:
run:
working_directory: ./my-app
steps:
- name: My first step
run: pwd # prints: /home/expo/workingdir/build/my-app
You can control when jobs run and what jobs must complete successfully before a job runs using the needs
and after
keywords. In addition, you can use the if
keyword to control whether a job should run based on a condition.
jobs.<job_id>.needs
A list of job IDs that must complete successfully before this job will run.
jobs:
test:
steps:
- uses: eas/checkout
- uses: eas/use_npm_token
- uses: eas/install_node_modules
- name: tsc
run: yarn tsc
build:
needs: [test] # This job will only run if the 'test' job succeeds
type: build
params:
platform: ios
jobs.<job_id>.after
A list of job IDs that must complete (successfully or not) before this job will run.
jobs:
build:
type: build
params:
platform: ios
notify:
after: [build] # This job will run after build completes (whether build succeeds or fails)
jobs.<job_id>.if
The if
conditional determines if a job should run.
jobs:
my_job:
if: ${{ github.ref == 'refs/heads/main' }}
jobs.<job_id>.type
Specifies the type of pre-packaged job to run. Pre-packaged jobs produce specialized UI according to the type of job on the workflow's detail page.
jobs:
my_job:
type: build
Learn about the different pre-packaged jobs below.
build
Creates an Android or iOS build of your project using EAS Build.
jobs:
my_job:
type: build
params:
platform: ios | android # required
profile: string # optional, default: production
Build jobs can be customized so that you can execute custom commands during the build process. See Custom builds for more information.
deploy
Deploys your application using EAS Hosting.
jobs:
my_job:
type: deploy
params:
alias: string # optional
prod: boolean # optional
get-build
Retrieves an existing build from EAS that matches the provided parameters.
jobs:
my_job:
type: get-build
params:
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
submit
Submits an Android or iOS build to the app store using EAS Submit. For environment
it uses the environment used to create build referenced in build_id
.
jobs:
my_job:
type: submit
params:
build_id: string # required
profile: string # optional, default: production
update
Publishes an update using EAS Update.
jobs:
my_job:
type: update
params:
message: string # optional
platform: string # optional - android, ios, or all
branch: string # optional
channel: string # optional - cannot be used with branch
maestro
Runs Maestro tests on a build.
maestro:
type: maestro
environment: production | preview | development # optional, defaults to preview
image: string # optional, defaults to 'default'. See https://docs.expo.dev/build-reference/infrastructure/ for a list of available images.
params:
build_id: string # required
flow_path: string | string[] # required
Runs custom code and can use built-in EAS functions. Does not require a type
field.
jobs:
my_job:
steps:
# ...
jobs.<job_id>.runs_on
Specifies the worker that will execute the job. Available only on custom jobs.
jobs:
my_job:
runs_on: linux-medium | linux-large | linux-medium-nested-virtualization | linux-large-nested-virtualization | macos-medium | macos-large
Worker | vCPU | Memory (GiB RAM) | SSD (GiB) | Notes |
---|---|---|---|---|
linux-medium | 4 | 16 | 14 | Default worker. |
linux-large | 8 | 32 | 28 | |
linux-medium-nested-virtualization | 4 | 16 | 14 | Allows running Android emulators. |
linux-large-nested-virtualization | 4 | 16 | 28 | Allows running Android emulators. |
macos-medium | 5 | 12 | 85 | Runs iOS jobs, including simulators. |
macos-large | 10 | 20 | 85 | Runs iOS jobs, including simulators. |
Note: For iOS builds and iOS simulator jobs, you must use a macos-*
worker. For Android emulator jobs, you must use a linux-*-nested-virtualization
worker.
jobs.<job_id>.outputs
A list of outputs for the job. Job outputs are available to all downstream jobs that depend on this job. Set outputs in a step using the set-output
function.
In the example below, the set-output
function sets the test
output to hello world
in job_1
's step_1
step. Later in job_2
, it's accessed in step_2
using needs.job_1.outputs.output_1
.
jobs:
job_1:
outputs:
output_1: ${{ steps.step_1.outputs.test }}
steps:
- id: step_1
run: set-output test "hello world"
job_2:
needs: [job_1]
steps:
- id: step_2
run: echo ${{ needs.job_1.outputs.output_1 }}
jobs.<job_id>.steps
A job contains a sequence of tasks called steps
. Steps can run commands.
jobs:
my_job:
steps:
- name: My first step
run: echo "Hello World"
jobs.<job_id>.steps.<step>.id
The id
property is used to reference the step in the job. Useful for using the step's output in a downstream job.
jobs:
my_job:
outputs:
test: ${{ steps.step_1.outputs.test }} # References the output from step_1
steps:
- id: step_1
run: set-output test "hello world"
jobs.<job_id>.steps.<step>.name
The name of the step, which is displayed in the job's logs.
jobs:
my_job:
steps:
- name: My first step
run: echo "Hello World"
jobs.<job_id>.steps.<step>.run
The command to run in the step.
jobs:
my_job:
steps:
- run: echo "Hello World"
jobs.<job_id>.steps.<step>.working_directory
The directory to run the command in. When defined at the step level, it overrides the jobs.<job_id>.defaults.run.working_directory
setting on the job if it is also defined.
jobs:
my_job:
steps:
- uses: eas/checkout
- run: pwd # prints: /home/expo/workingdir/build/my-app
working_directory: ./my-app
jobs.<job_id>.steps.<step>.uses
EAS provides a set of built-in reusable functions that you can use in workflow steps. The uses
keyword is used to specify the function to use. All built-in functions start with the eas/
prefix.
jobs:
my_job:
steps:
- uses: eas/checkout
- uses: eas/install_node_modules
- uses: eas/prebuild
- name: List files
run: ls -la
Below is a list of built-in functions you can use in your workflow steps.
eas/checkout
Checks out your project source files.
jobs:
my_job:
steps:
- uses: eas/checkout
View the source code for the eas/checkout function on GitHub.
eas/install_node_modules
Installs node modules using the package manager (bun, npm, pnpm, or Yarn) detected based on your project. Works with monorepos.
jobs:
my_job:
steps:
- uses: eas/checkout
- uses: eas/install_node_modules
View the source code for the eas/install_node_modules function on GitHub.
eas/prebuild
Runs the expo prebuild
command using the package manager (bun, npm, pnpm, or Yarn) detected based on your project with the command best suited for your build type and build environment.
jobs:
my_job:
steps:
- uses: eas/checkout
- uses: eas/install_node_modules
- uses: eas/prebuild
jobs:
my_job:
steps:
- uses: eas/checkout
- uses: eas/install_node_modules
- uses: eas/resolve_apple_team_id_from_credentials
id: resolve_apple_team_id_from_credentials
- uses: eas/prebuild
with:
clean: false
apple_team_id: ${{ steps.resolve_apple_team_id_from_credentials.outputs.apple_team_id }}
Property | Type | Description |
---|---|---|
clean | boolean | Optional property defining whether the function should use --clean flag when running the command. Defaults to false. |
apple_team_id | string | Optional property defining Apple team ID which should be used when doing prebuild. It should be specified for iOS builds using credentials. |
View the source code for the eas/prebuild function on GitHub.
eas/send_slack_message
Sends a specified message to a configured Slack webhook URL, which then posts it in the related Slack channel.
The message can be specified as plaintext or as a Slack Block Kit message.
With both cases, you can reference build job properties and use other steps outputs in the message for dynamic evaluation.
For example, 'Build URL: ${{ eas.job.expoBuildUrl }}'
, Build finished with status: ${{ steps.run_fastlane.status_text }}
, Build failed with error: ${{ steps.run_gradle.error_text }}
.
Either "message" or "payload" has to be specified, but not both.
jobs:
my_job:
steps:
- uses: eas/send_slack_message
with:
message: 'This is a message to plain input URL'
slack_hook_url: 'https://hooks.slack.com/services/[rest_of_hook_url]'
Property | Type | Description |
---|---|---|
message | string | The text of the message you want to send. For example, 'This is the content of the message' .Note: Either message or payload needs to be provided, but not both. |
payload | string | The contents of the message you want to send which are defined using Slack Block Kit layout. Note: Either message or payload needs to be provided, but not both. |
slack_hook_url | string | The URL of the previously configured Slack webhook URL, which will post your message to the specified channel. You can provide the plain URL like slack_hook_url: 'https://hooks.slack.com/services/[rest_of_hook_url]' , use EAS secrets like slack_hook_url: ${{ eas.env.ANOTHER_SLACK_HOOK_URL }} , or set the SLACK_HOOK_URL secret, which will serve as a default webhook URL (in this last case, there is no need to provide the slack_hook_url property). |
View the source code for the eas/send_slack_message function on GitHub.
eas/use_npm_token
Configures node package managers (bun, npm, pnpm, or Yarn) for use with private packages, published either to npm or a private registry.
Set NPM_TOKEN
in your project's secrets, and this function will configure the build environment by creating .npmrc with the token.
jobs:
my_job:
name: Install private npm modules
steps:
- uses: eas/checkout
- uses: eas/use_npm_token
- name: Install dependencies
run: npm install # <---- Can now install private packages
View the source code for the eas/use_npm_token function on GitHub.