This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
Custom build configuration schema
Edit page
A reference of configuration options for custom builds with EAS Build.
Creating custom builds for EAS Build helps customize the build process for your project.
YAML syntax for custom builds
Custom build config files are stored inside the .eas/build directory path. They use YAML syntax and must have a .yml or .yaml file extension. If you are new to YAML or want to learn more about the syntax, see Learn YAML in Y minutes.
build
Defined to describe a custom build configuration. All config options to create a custom build are specified under it.
name
The name of your custom build that is used to identify it in the build logs. EAS Build uses this property to display the name of your build in the dashboard.
For example, the build name is Run tests:
build: name: Run tests steps: - eas/checkout - run: name: Install dependencies command: npm install
steps
Steps are used to describe a list of actions, either in the form of commands or function calls. These actions are executed when a custom build runs on EAS Build. You can define single or multiple steps in a build config. However, it is required to define at least one step per build.
Each step is configured with the following properties:
steps[].run
The run key is used to trigger a set of instructions. For example, a run key is used to install dependencies using the npm install command:
build: name: Install npm dependencies steps: - eas/checkout - run: name: Install dependencies command: npm install
You can also use steps[].run to execute single or multiline shell commands:
build: name: Run inline shell commands steps: - run: echo "Hello world" - run: | echo "Multiline" echo "bash commands"
Use a single step
For example, a build config with the following steps will print "Hello world":
build: name: Greeting steps: - run: echo "Hello world"
Note:
-beforeruncounts as indentation.
Use multiple steps
When multiple steps are defined, they are executed sequentially. For example, a build config with the following steps will first check out the project, install npm dependencies, and then run a command to run tests:
build: name: Run tests steps: - eas/checkout - run: name: Install dependencies command: npm install - run: name: Run tests command: | echo "Running tests..." npm test
Sharing environment variables with other steps
Environment variables exported (using export) in one step's command are not automatically exposed to other steps. To share an environment variable with other steps, use the set-env executable.
set-env expects to be called with two arguments: environment variable's name and value. For example, set-env NPM_TOKEN "abcdef" will expose $NPM_TOKEN variable with value abcdef to other steps.
Note: Variables shared with
set-envare not automatically exported locally. You need to callexportyourself.
build: name: Shared environment variable example steps: - run: name: Set environment variables command: | set -x # Set variable ENV_TEST_LOCAL="present-only-in-current-shell-context" # Set and export variable export ENV_TEST_LOCAL_EXPORT="present-in-current-step" # Set shared variable set-env ENV_TEST_SET_ENV "present-in-following-steps" # Will print "ENV_TEST_LOCAL: present-only-in-current-shell-context" # because current shell has access to this local variable. echo "ENV_TEST_LOCAL: $ENV_TEST_LOCAL" # Will print "ENV_TEST_LOCAL_EXPORT: present-in-current-step" # because export also sets the local variable value. echo "ENV_TEST_LOCAL_EXPORT: $ENV_TEST_LOCAL_EXPORT" # Will "ENV_TEST_SET_ENV: " # because set-env does not set or export variables. echo "ENV_TEST_SET_ENV: $ENV_TEST_SET_ENV" # Will only print LOCALLY_EXPORTED_ENV, # because it is the only export-ed variable. env | grep ENV_TEST_ - run: name: Check variables values in next step command: | set -x # Will print "ENV_TEST_LOCAL: ", because ENV_TEST_LOCAL # is only a local variable in previous step. echo "ENV_TEST_LOCAL: $ENV_TEST_LOCAL" # Will print "ENV_TEST_LOCAL_EXPORT: " # because export does not share a variable to other steps. echo "ENV_TEST_LOCAL_EXPORT: $ENV_TEST_LOCAL_EXPORT" # Will print "ENV_TEST_SET_ENV: present-in-following-steps" # because set-env "exported" variable to other steps. echo "ENV_TEST_SET_ENV: $ENV_TEST_SET_ENV" # Will only print ENV_TEST_SET_ENV, # because set-env "exported" it to other steps. env | grep ENV_TEST_
steps[].run.name
The name used in build logs to display the name of the step.
steps[].run.command
The command defines a custom shell command to run when a step is executed. It is required to define a command for each step. It can be a multiline shell command:
build: name: Run tests steps: - eas/checkout - run: name: Run tests command: | echo "Running tests..." npm test
steps[].run.working_directory
The working_directory is used to define an existing directory from the project's root directory. After an existing path is defined in a step, using it changes the current directory for that step. For example, a step is created to list all the assets inside the assets directory, which is a directory in your Expo project. The working_directory is set to assets:
build: name: Demo steps: - eas/checkout - run: name: List assets working_directory: assets command: ls -la
steps[].run.shell
Used to define the default executable shell for a step. For example, the step's shell is set to /bin/sh:
build: name: Demo steps: - run: shell: /bin/sh command: | echo "Steps can use another shell" ps -p $$
steps[].run.inputs
Input values are provided to a step. For example, you can use input to provide a value:
build: name: Demo steps: - run: name: Say Hi inputs: name: Expo command: echo "Hi, ${ inputs.name }!"
steps[].run.outputs
An output value is expected during a step. For example, a step has an output value of Hello world:
build: name: Demo steps: - run: name: Produce output outputs: [value] command: | echo "Producing output for another step" set-output value "Output from another step..."
steps[].run.outputs.required
An output value can use a boolean to indicate if the output value is required or not. For example, a function does not have a required output value:
build: name: Demo steps: - run: name: Produce another output id: id456 outputs: - required_param - name: optional_param required: false command: | echo "Producing more output" set-output required_param "abc 123 456"
steps[].run.id
Defining an id for a step allows:
- Calling the same function that produces one or more outputs multiple times
- Using the output from one step to another
Call the same function one or more times
For example, the following function generates a random number:
functions: random: name: Generate random number outputs: [value] command: set-output value `random_number`
In a build config, let's use the random function to generate two random numbers and print them:
build: name: Functions Demo steps: - random: id: random_1 - random: id: random_2 - run: name: Print random numbers inputs: random_1: ${ steps.random_1.value } random_2: ${ steps.random_2.value } command: | echo "${ inputs.random_1 }" echo "${ inputs.random_2 }"
Use output from one step to another
For example, the following build config demonstrates how to use output from one step to another:
build: name: Outputs demo steps: - run: name: Produce output id: id123 # <---- !!! outputs: [foo] command: | echo "Producing output for another step" set-output foo bar - run: name: Use output from another step inputs: foo: ${ steps.id123.foo } command: | echo "foo = \"${ inputs.foo }\""
functions
Defined to describe a reusable function that can be used in a build config. All config options to create a function are specified with the following properties:
functions.[function_name]
The [function_name] is the name of a function that you define to identify it in the build.steps. For example, you can define a function with the name greetings:
functions: greetings: name: Say Hi!
functions.[function_name].name
The name that is used in build logs to display the name of the function. For example, a function with the display name Say Hi!:
functions: greetings: name: Say Hi!
functions.[function_name].inputs
Input values are provided to a function.
inputs[].name
The name of the input value. It is used as an identifier to access the input value such as in bash command interpolation.
functions: greetings: name: Say Hi! inputs: - name: name default_value: Hello world command: echo "${ inputs.name }!"
inputs[].required
Boolean to indicate if the input value is required or not. For example, a function does not have a required value:
functions: greetings: name: Say Hi! inputs: - name: name required: false
inputs[].type
The type of the input value. It can be either string, num or json.
Input values set in the function call as well as default_value and allowed_values for the function are validated against the type.
The default input type is string.
For example, a function has an input value of type string:
functions: greetings: name: Say Hi! inputs: - name: name type: string - name: age type: num - name: other_data type: json
inputs[].default_value
You can use default_value to provide one default input. For example, a function has a default value of Hello world:
functions: greetings: name: Say Hi! inputs: - name: name default_value: Hello world
inputs[].allowed_values
You can use allowed_values to provide multiple values in an array. For example, a function has multiple allowed values:
functions: greetings: name: Say Hi! inputs: - name: name default_value: Hello world allowed_values: [Hi, Hello, Hey] type: string
Multiple input values
Multiple input values can be provided to a function.
functions: greetings: name: Say Hi! inputs: - name: name default_value: Expo - name: greeting default_value: Hi allowed_values: [Hi, Hello] command: echo "${ inputs.greeting }, ${ inputs.name }!"
functions.[function_name].outputs
An output value is expected from a function. For example, a function has an output value of Hello world:
functions: greetings: name: Say Hi! outputs: [value] command: set-output value "Hello world"
outputs[].name
The name of the output value. It is used as an identifier to access the output value in another step:
functions: greetings: name: Say Hi! outputs: - name: name
outputs[].required
Boolean to indicate if the output value is required or not. For example, a function does not have a required output value:
functions: greetings: name: Say Hi! outputs: - name: value required: false
functions.[function_name].command
Used to define the command to run when a function is executed, if you wish the function to be a simple shell script. Each function is required to define either a command or a path to JS/TS module implementing the function. For example, the command echo "Hello world" is used to print a message:
functions: greetings: name: Say Hi! command: echo "Hi!"
functions.[function_name].path
Used to define the path to a JavaScript/TypeScript module implementing the function. Each function is required to define either a command or a path property. For example, the path ./greetings is used to execute a greetings function declared in the greetings module:
functions: greetings: name: Say Hi! path: ./greetings
functions.[function_name].shell
Used to define the default executable shell for a step where a function is executed. For example, the step's shell is set to /bin/sh:
functions: greetings: name: Say Hi! shell: /bin/sh command: echo "Hi!"
functions.[function_name].supported_platforms
Used to define the supported platforms for a function. Defaults to all platforms. Allowed platforms: darwin, linux.
For example, the function's supported platform is darwin (macOS):
functions: greetings: name: Say Hi! supported_platforms: [darwin] command: echo "Hi!"
import
A config file path list used to import functions from other config files. Imported files cannot have the build section.
For example, the following build config imports two files and calls two imported functions - say_hi and say_bye.
Functions
Built-in EAS functions
EAS provides a set of built-in reusable functions that you can use in a build config without defining the function definition.
Tip: Any function that is built-in and provided by EAS must start with the
eas/prefix.
eas/build
The all-in-one function that encapsulates the entire EAS Build build process. It resolves the best build configuration based on your build profile's settings from eas.json.
It's ideal for people who want to have the build done without worrying about altering and configuring the build process manually. It can be a great starting point for your custom build configuration if you are interested in using other custom steps before or after the build process and you don't want to change the build process itself.
To have more control over the build process and customize it as per your requirements, see the following custom functions and steps that run in the background by eas/build. They are executed as a build process based on your build profile's configuration.
Android
When a build configuration is using withoutCredentials:
eas/checkouteas/use_npm_tokeneas/install_node_moduleseas/resolve_build_configeas/prebuildeas/configure_eas_updateeas/run_gradleeas/find_and_upload_build_artifacts
When a build configuration uses credentials (for both internal and store distribution builds):
eas/checkouteas/use_npm_tokeneas/install_node_moduleseas/resolve_build_configeas/prebuildeas/configure_eas_updateeas/inject_android_credentialseas/configure_android_versioneas/run_gradleeas/find_and_upload_build_artifacts
iOS
When a build configuration is using withoutCredentials or simulator:
eas/checkouteas/use_npm_tokeneas/install_node_moduleseas/resolve_build_configeas/prebuild- Install pods using the
pod installcommand eas/configure_eas_updateeas/generate_gymfile_from_templateeas/run_fastlaneeas/find_and_upload_build_artifacts
When a build configuration uses credentials (for both internal and store distribution builds):
eas/checkouteas/use_npm_tokeneas/install_node_moduleseas/resolve_build_configeas/resolve_apple_team_id_from_credentialseas/prebuild- Install pods using the
pod installcommand eas/configure_eas_updateeas/configure_ios_credentialseas/configure_ios_versioneas/generate_gymfile_from_templateeas/run_fastlaneeas/find_and_upload_build_artifacts
You can replace the eas/build command call by using these steps in your YAML configuration file:
View the steps executed behind the scenes by the `eas/build` function for an iOS simulator build in our example repository.
View the steps executed behind the scenes by the `eas/build` function for an iOS build with credentials in our example repository.
View the steps executed behind the scenes by the `eas/build` function for an Android build without credentials in our example repository.
View the steps executed behind the scenes by the `eas/build` function for an Android build with credentials in our example repository.
Known limitations
- It doesn't accept any inputs, and the resolved build process will be configured based on your build profile from eas.json.
- The build process produced by
eas/buildis not configurable and you can't customize it. If you need to customize the build process, use the subset of functions and steps that are executed behind the scenes by this function and configure them manually in the YAML configuration file, as shown in the examples above.
eas/maestro_test
All-in-one function that installs Maestro, prepares a testing environment (Android Emulator or iOS Simulator), and tests the app.
Your project must be configured to use the old Build Infrastructure to start Android Emulator. Go to Project settings to configure. See this changelog post for more information.
Behind the scenes, it uses:
eas/install_maestroto install Maestroeas/start_android_emulatorto start an Android Emulator if neededeas/start_ios_simulatorto start an iOS Simulator if needed- Custom
runto install .apk to the running Android Emulator and .app to iOS Simulator - Series of
runto executemaestro testfor each of the provided flows eas/upload_artifactto upload Maestro test artifacts as build artifact
We have observed that Maestro tests often time out if run on images with Xcode 15.0 or 15.2. Use the
latestimage to avoid any issues.
If you need to customize the Maestro version, run a specific Android Emulator or iOS Simulator, or upload multiple build artifacts you will need to write this series of steps yourself.
View the source code for the eas/maestro_test function on GitHub.
eas/checkout
Checks out your project source files.
For builds with Git-based project sources, the step uses the build's recorded commit by default. Use ref to check out a different branch, tag, or commit:
ref accepts:
- A branch, as a bare name such as
feature/add-iconor a qualified ref such asrefs/heads/feature/add-icon. The repository ends up on that branch. - A tag, as a qualified ref such as
refs/tags/v1.2.3. The repository ends up on a detachedHEAD. - A full commit SHA. The repository ends up on a detached
HEAD.
The ref input only works when your project sources come from a Git repository, for example, a build triggered through the GitHub integration. Local builds and uploaded project tarballs do not support it. Place the step before eas/build, which checks out the project internally.
View the source code for the eas/checkout 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.
View the source code for the eas/use_npm_token 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.
View the source code for the eas/install_node_modules function on GitHub.
eas/restore_build_cache
Restores a previously saved build cache from a specified key. This is useful for speeding up builds by reusing cached artifacts like compiled dependencies, build tools, or other intermediate build outputs.
View the source code for the eas/restore_build_cache function on GitHub.
eas/save_build_cache
Saves a build cache to a specified key. This allows you to persist build artifacts, compiled dependencies, or other intermediate outputs that can be reused in subsequent builds to speed up the build process.
View the source code for the eas/save_build_cache function on GitHub.
eas/resolve_build_config
Resolves and prints the build configuration. If the build has been triggered by the GitHub integration, it will update the current job and metadata context values. It should be called after installing the dependencies because the config may be influenced by config plugins.
This function is automatically executed by the eas/build function group.
View the source code for the eas/resolve_build_config function on GitHub.
eas/get_credentials_for_build_triggered_by_github_integration
Deprecated: Replace this step with
eas/resolve_build_config.
eas/resolve_apple_team_id_from_credentials
This function is only available for iOS builds.
Resolves the Apple team ID value based on build credentials provided in the inputs.credentials. The resolved Apple team ID is stored in the outputs.apple_team_id output value.
View the source code for the eas/resolve_apple_team_id_from_credentials 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.
View the source code for the eas/prebuild function on GitHub.
eas/configure_eas_update
To use this function you need to have EAS Update configured for your project.
Configures runtime version and release channel for your build.
View the source code for the eas/configure_eas_update function on GitHub.
eas/inject_android_credentials
This function is only available for Android builds.
Configures Android keystore with credentials on the builder and injects app signing config using these credentials into gradle config.
View the source code for the eas/inject_android_credentials function on GitHub.
eas/configure_ios_credentials
This function is only available for iOS builds.
Configures iOS credentials on the builder. Modifies the configuration of the Xcode project by assigning provisioning profiles to the targets.
View the source code for the eas/configure_ios_credentials function on GitHub.
eas/configure_android_version
This function is only available for Android builds.
Configures the version of your Android app. It's used to set a version when using remote app version management.
It's not mandatory to use this function, if it's not used the version from native code generated during the prebuild phase will be used.
View the source code for the eas/configure_android_version function on GitHub.
eas/configure_ios_version
This function is only available for iOS builds.
Configures the version of your iOS app. It's used to set a version when using remote app version management.
It's not mandatory to use this function, if it's not used the version from native code generated during the prebuild phase will be used.
View the source code for the eas/configure_ios_version function on GitHub.
eas/run_gradle
This function is only available for Android builds.
Runs a Gradle command to build an Android app.
View the source code for the eas/run_gradle function on GitHub.
eas/generate_gymfile_from_template
This function is only available for iOS builds.
Generates a Gymfile used to build the iOS app using Fastlane from a template.
Default template used when credentials are passed:
Default template used when credentials are not passed (simulator build):
CLEAN, SCHEME, BUILD_CONFIGURATION, EXPORT_METHOD, PROFILES, ICLOUD_CONTAINER_ENVIRONMENT, KEYCHAIN_PATH, LOGS_DIRECTORY, OUTPUT_DIRECTORY, DERIVED_DATA_PATHand SCHEME_SIMULATOR_DESTINATION values are provided to the template based on the inputs and default internal configuration of EAS Build.
However, you can also use other custom properties in the template, by specifying your custom template in inputs.template and providing the values for the custom properties in the inputs.extra object.
View the source code for the eas/generate_gymfile_from_template function on GitHub.
eas/run_fastlane
This function is only available for iOS builds.
Runs fastlane gym command against the Gymfile located in the ios project directory to build the iOS app.
View the source code for the eas/run_fastlane function on GitHub.
eas/find_and_upload_build_artifacts
You can currently upload each artifact type only once per build job.
If you useeas/find_and_upload_build_artifactswhile havingbuildArtifactPathsconfigured in your build profile and the step finds and uploads some build artifacts, any followingeas/upload_artifactstep will fail.
To solve this, for now, we recommend removingbuildArtifactPathsfrom custom build's profiles and uploading artifacts manually witheas/upload_artifactin the YAML if you need to call it there.
Automatically finds and uploads application archive, additional build artifacts, and Xcode logs from the default locations and using the buildArtifactPaths configuration. Uploads found artifacts to the EAS servers.
View the source code for the eas/find_and_upload_build_artifacts function on GitHub.
eas/upload_artifact
Uploads files from the job's workspace as an artifact attached to the run. Uploaded artifacts appear in the run's Artifacts section and can be retrieved in a later job with eas/download_artifact.
You can currently upload each artifact type only once per build job.
If you useeas/find_and_upload_build_artifactswhile havingbuildArtifactPathsconfigured in your build profile and the step finds and uploads some build artifacts, any followingeas/upload_artifactstep will fail.
To solve this, for now, we recommend removingbuildArtifactPathsfrom custom build's profiles and uploading artifacts manually witheas/upload_artifactin the YAML if you need to call it there.
Outputs
View the source code for the eas/upload_artifact function on GitHub.
eas/install_maestro
Makes sure Maestro, the mobile UI testing framework, is installed along with all its dependencies.
View the source code for the eas/install_maestro function on GitHub.
eas/start_android_emulator
Starts an Android Emulator you can use to test your apps on. Only available when running a build for Android.
Your project must be configured to use the old Build Infrastructure to start Android Emulator. Go to Project settings to configure. See this changelog post for more information.
View the source code for the eas/start_android_emulator function on GitHub.
eas/start_ios_simulator
Starts an iOS Simulator you can use to test your apps on. Only available when running a build for iOS.
View the source code for the eas/start_ios_simulator 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.
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 }.
View the source code for the eas/send_slack_message function on GitHub.
The following functions connect your build to PostHog. Run eas integrations:posthog:connect to link a PostHog project and set the environment variables these functions read. eas/posthog_capture_event uses your public project API key, while the other functions use a PostHog personal API key with the scopes noted for each one. For setup, see Using PostHog, and for complete workflows, see PostHog recipes for EAS Workflows.
eas/posthog_capture_event
Sends an analytics event to PostHog. Use it to mark builds, releases, and other milestones on your PostHog timeline.
When you do not provide a distinct_id, the event is sent anonymously and does not create a PostHog person profile.
View the source code for the eas/posthog_capture_event function on GitHub.
eas/posthog_flag_rollout
Enables, disables, or rolls out a PostHog feature flag. The function looks up the flag by key and then updates it. Provide at least one of active, rollout_percentage, or payload.
View the source code for the eas/posthog_flag_rollout function on GitHub.
eas/posthog_wait_for_metric
Pauses until a HogQL query returns a number that satisfies a comparison. Use it to gate on a metric, such as holding until the error count over the last few minutes stays low. The function runs the query every interval_seconds until the comparison is true or timeout_seconds elapses.
This step has no
ignore_errorinput. A timeout or an unreadable query always fails the step.
Outputs
View the source code for the eas/posthog_wait_for_metric function on GitHub.
eas/posthog_wait_for_query
Pauses until a HogQL query returns true. Use it when the condition is easier to express in the query itself. For a numeric comparison with an explicit threshold, use eas/posthog_wait_for_metric instead. The step clears when the first column of the first row is true or a nonzero number.
Like
eas/posthog_wait_for_metric, this step has noignore_errorinput. A timeout or an unreadable query always fails the step.
View the source code for the eas/posthog_wait_for_query function on GitHub.
eas/posthog_annotation
Creates a PostHog annotation on the project timeline. Annotations show up on your PostHog charts, which makes them useful for marking builds, releases, and other milestones next to the metrics they affect.
View the source code for the eas/posthog_annotation function on GitHub.
eas/posthog_upload_sourcemaps
Uploads JavaScript source maps to PostHog so that PostHog symbolicates stack traces in error tracking. Run it after the step that produces your bundle, in the same job, so the bundle and source maps are available on disk. Export with npx expo export --source-maps, and configure the PostHog Metro config from the Source maps guide so bundles carry the chunk IDs that match them to their source maps.
This step runs the PostHog CLI, which cannot tell a permissions error apart from any other failure. Unlike the other PostHog functions, setting
ignore_error: truealso hides authentication and scope errors.
View the source code for the eas/posthog_upload_sourcemaps function on GitHub.
Using built-in EAS functions to build an app
Using the built-in EAS functions you can recreate the default EAS Build process for different build types.
For example, to trigger a build that creates internal distribution build for Android and a simulator build for iOS you can use the following configuration:
To create a Google Play Store build for Android and an Apple App Store build for iOS you can use the following configuration:
Check out the example repository for more detailed examples:
A custom EAS Build example that includes examples for custom builds such as setting up functions, using environment variables, uploading artifacts, and more.
Use a reusable function in a build
For example, a custom build config with the following reusable function contains a single command to print a message that is echoed.
functions: greetings: - name: name default_value: Hello world inputs: [value] command: echo "${ inputs.name }, { inputs.value }"
The above function can be used in a build as follows:
build: name: Functions Demo steps: - greetings: inputs: value: Expo
Tip:
build.stepscan execute multiple reusablefunctionssequentially.
Override values in a build
You can override values for the following properties:
working_directorynameshell
For example, a reusable function called list_files:
functions: list_files: name: List files command: ls -la
When list_files is called in a build config, it lists all files in the root directory of a project:
build: name: List files steps: - eas/checkout - list_files
You can use the working_directory property to override the behavior in the function call to list the files in a different directory by specifying the path to that directory:
build: name: List files steps: - eas/checkout - list_files: working_directory: /a/b/c