---
title: Concurrency groups and hooks for Workflows
authors: Ash Wu
published: November 9, 2026
---



## Concurrency groups

Until now, `concurrency` could do one thing: `cancel_in_progress: true` canceled the in-progress runs of the same workflow on the same branch, for runs started from GitHub. The `group` key was a placeholder, and there was no way to make a run wait.

`group` is now a real template. Runs whose key renders to the same value belong to one group, within a project and across workflow files. You decide what a new run does to the rest of its group: cancel them, or wait for them. `cancel_in_progress` accepts an expression, so the choice can depend on the run. A waiting run shows as **Queued** in the EAS dashboard and uses no build minutes until it starts.

```yaml
concurrency:
  group: ${{ workflow.filename }}-${{ github.ref }}
  cancel_in_progress: ${{ github.ref_name != 'main' }}
```

With this configuration, a push to a feature branch cancels the stale runs of that branch, while a run on `main` waits for the active one to finish, so a deploy is never interrupted. For workflows where every run must execute, such as migrations, `queue: max` keeps up to 100 runs waiting in order. See [`concurrency`](https://docs.expo.dev/eas/workflows/syntax/#concurrency) in the workflow syntax reference for the details.

## Hooks for pre-packaged jobs

Hooks add your own steps to a pre-packaged job, without rewriting it as a custom job. They used to be a patchwork of job-specific keys, only some of them documented. Hook support has expanded, and each job's docs now list its hooks:

- **Supported jobs:** build, deploy, fingerprint, repack, submit, testflight, update, and the two Maestro jobs.
- **Hook points:** add steps after checkout, before or after dependency installation, and around the main action of the submit, update, and Maestro jobs, for example `after_update` to upload sourcemaps after publishing an update.
- **Workflow-wide defaults:** `defaults.hooks` sets a hook once for every job that supports it.

```yaml
jobs:
  build_ios:
    type: build
    params:
      platform: ios
    hooks:
      before_install_node_modules:
        # GITHUB_TOKEN comes from your EAS environment variables
        - run: echo "//npm.pkg.github.com/:_authToken=$GITHUB_TOKEN" >> .npmrc
```

Each job's section in [pre-packaged jobs](https://docs.expo.dev/eas/workflows/pre-packaged-jobs/) lists its hook keys, with examples such as uploading sourcemaps to PostHog from an `after_update` hook. Learn more about [`hooks`](https://docs.expo.dev/eas/workflows/syntax/#jobsjob_idhooks) and [`defaults.hooks`](https://docs.expo.dev/eas/workflows/syntax/#defaultshooks) in the workflow syntax reference.

## Wrap up

Both features are available now. If you run into problems, or there is a hook point you wish existed, let us know on [Discord](https://chat.expo.dev/) or [X](https://x.com/expo).