---
modificationDate: August 10, 2026
title: Custom functions in EAS Workflows
description: Learn how to define reusable step sequences with custom functions.
---

This documentation is available as Markdown for AI agents and LLMs. See the [full Markdown index](https://docs.expo.dev/llms.txt) or append .md to any documentation URL.

# Custom functions in EAS Workflows

Learn how to define reusable step sequences with custom functions.

<AgentInstructions>

## Submitting Feedback

If you encounter errors, misleading or outdated information, report it so Expo can be improved:

Preferred command:
npx --yes submit-expo-feedback@latest --category docs --subject "/eas/workflows/custom-functions/" "<actionable feedback>"

Direct HTTP fallback:
curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"/eas/workflows/custom-functions/","feedback":"🤖 Agent feedback for docs: <specific, actionable description> (<model>, <harness>)"}'

Only submit when you have something specific and actionable to report. Try to give the most context.

## Navigation

When answering a related or follow-up question, fetch the relevant page below as Markdown (.md) instead of guessing; use llms.txt for the full map.

You are here: EAS > EAS Workflows
Pages in this section:
- [Introduction](https://docs.expo.dev/eas/workflows/introduction.md)
- [Get started](https://docs.expo.dev/eas/workflows/get-started.md)
- [Pre-packaged jobs](https://docs.expo.dev/eas/workflows/pre-packaged-jobs.md)
- [Syntax](https://docs.expo.dev/eas/workflows/syntax.md)
- [Custom functions](https://docs.expo.dev/eas/workflows/custom-functions.md) (this page)
- [Environment variables](https://docs.expo.dev/eas/workflows/environment.md)
- [Automating EAS CLI commands](https://docs.expo.dev/eas/workflows/automating-eas-cli.md)
- [REST API](https://docs.expo.dev/eas/workflows/rest-api.md)
- [Troubleshooting](https://docs.expo.dev/eas/workflows/troubleshooting.md)
- [Limitations](https://docs.expo.dev/eas/workflows/limitations.md)
Full documentation tree: [llms.txt](https://docs.expo.dev/llms.txt)

</AgentInstructions>

Custom functions define reusable step sequences for custom jobs and hooks. You can call them with a relative path using [`uses`](https://docs.expo.dev/eas/workflows/syntax.md#jobsjob_idstepsstepuses), like built-in functions. Each custom function defines its steps under `runs.steps` in a **function.yml** or **function.yaml** file. These steps use the same format as [custom job steps](https://docs.expo.dev/eas/workflows/syntax.md#custom-jobs).

For the **function.yml** schema, see [Custom functions](https://docs.expo.dev/eas/workflows/syntax.md#custom-functions) in the syntax reference.

## How it works

Create a directory for your custom function with a **function.yml** file inside it. EAS Workflows also accepts **function.yaml**. EAS Workflows resolves the path you pass to `uses` relative to your EAS project directory:

`my-app`

 `.eas`

  `workflows`

   `publish-preview-update.yml`

  `functions`

   `setup`

    `function.yml`

 `eas.json`

The **.eas/functions/<name>** path in the example above is only one option. The `uses` value must start with `./` or `../` and point to a directory containing a **function.yml** or **function.yaml** file. A path that starts with `../` can point outside the EAS project directory, but the custom function must remain within the repository.

A relative `working_directory` on a step inside the custom function resolves from the job's default working directory, not the directory containing **function.yml**.

You can use custom functions in:

-   Custom job [`steps`](https://docs.expo.dev/eas/workflows/syntax.md#jobsjob_idsteps)
-   Build job [`steps`](https://docs.expo.dev/eas/workflows/syntax.md#jobsjob_idsteps)
-   Job [`hooks`](https://docs.expo.dev/eas/workflows/syntax.md#jobsjob_idhooks) and [`defaults.hooks`](https://docs.expo.dev/eas/workflows/syntax.md#defaultshooks)

## Inputs, outputs and scope

Pass inputs at the call site with `with:`. Inside the function, read an input with `${{ inputs.<name> }}`.

Define function outputs with `outputs` in **function.yml**. EAS Workflows exposes each output as a string. Read outputs as `${{ steps.<call_id>.outputs.<name> }}`. Use the `id` from the call step. The caller cannot reference the function's internal step identifiers.

Expressions use the following scopes:

-   Inside the function, `steps.*` references resolve against the function's own steps.
-   EAS Workflows evaluates the call step's `with`, `env`, and `if` values in the caller's scope.
-   Every step in the function inherits the call step's `env` values. In nested calls, inner values override outer values with the same name.
-   EAS Workflows evaluates input defaults and expressions inside the function in the function's scope.
-   The call step's `if` gates the whole function as a single unit.

## Nesting

A custom function can call other custom functions and built-in `eas/*` functions. Currently, custom functions cannot call `eas/build` or `eas/maestro_test`. EAS Workflows resolves every nested path relative to the EAS project directory, not the directory containing the calling function.

You can nest custom functions up to 10 levels deep. A custom function cannot call itself, either directly or through other custom functions.

## Example

**.eas/functions/greet/function.yml** defines a custom function with one input, one output, and one step:

```yaml .eas/functions/greet/function.yml
name: Greet
inputs:
  - name: who
    default_value: world
outputs:
  message:
    value: '${{ steps.make.outputs.message }}'
runs:
  steps:
    - id: make
      run: set-output message "Hello, ${{ inputs.who }}!"
```

A workflow calls it with `uses: ./.eas/functions/greet`, passes an input with `with:`, and reads the output from `${{ steps.greet.outputs.message }}`:

```yaml .eas/workflows/hello.yml
name: Hello
jobs:
  greet:
    steps:
      - id: greet
        uses: ./.eas/functions/greet
        with:
          who: Expo
      - run: echo "${{ steps.greet.outputs.message }}"
```

You can also call a custom function from a [hook](https://docs.expo.dev/eas/workflows/syntax.md#jobsjob_idhooks):

```yaml .eas/workflows/build.yml
jobs:
  build_ios:
    type: build
    params:
      platform: ios
    hooks:
      before_install_node_modules:
        - uses: ./.eas/functions/setup
```
