---
modificationDate: July 08, 2026
title: 'Create preview builds for pull requests with EAS Workflows'
description: Learn how to create preview build workflows for Slack notifications and PR previews using EAS Workflows.
---

<AgentInstructions>

## Submitting Feedback

If this page contains errors, outdated information, or gaps that blocked you from completing a task, report it so the docs can be improved:

curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"/tutorial/cicd/preview-builds/","feedback":"🤖 Agent feedback for docs: <specific, actionable description> (<model>, <harness>)"}'

Only submit when you have something specific and actionable to report. Replace <model> with the model you are running as and <harness> with the tool you are running in (for example, Claude Code, Cursor, Codex CLI).

## 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: Learn > CI/CD tutorial
Pages in this section:
- [Introduction](https://docs.expo.dev/tutorial/cicd/introduction.md)
- [First EAS Workflows job](https://docs.expo.dev/tutorial/cicd/first-workflow.md)
- [Development builds](https://docs.expo.dev/tutorial/cicd/development-builds.md)
- [Preview builds](https://docs.expo.dev/tutorial/cicd/preview-builds.md) (this page)
- [E2E tests](https://docs.expo.dev/tutorial/cicd/e2e-tests.md)
- [Production deployments](https://docs.expo.dev/tutorial/cicd/production.md)
- [Tag-based releases](https://docs.expo.dev/tutorial/cicd/tag-based-releases.md)
- [Web deployments](https://docs.expo.dev/tutorial/cicd/web-deployments.md)
- [Next steps](https://docs.expo.dev/tutorial/cicd/next-steps.md)
Full documentation tree: [llms.txt](https://docs.expo.dev/llms.txt)

</AgentInstructions>

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

# Create preview builds for pull requests with EAS Workflows

Learn how to create preview build workflows for Slack notifications and PR previews using EAS Workflows.

Sharing in-progress mobile changes with teammates and pull request (PR) reviewers often requires them to check out a branch and run a development server locally.

## Learning outcomes

-   Automate preview builds with fingerprinting for internal distribution
-   Post Slack notifications when a build finishes
-   Publish an [OTA update](/deploy/send-over-the-air-updates.md) on every pull request and comment on the PR with a link to test it

#### Prerequisites

##### expo-updates installed

Install the [`expo-updates`](/versions/latest/sdk/updates.md) library:

```sh
# npm
npx expo install expo-updates

# yarn
yarn dlx expo install expo-updates

# pnpm
pnpm dlx expo install expo-updates

# bun
bunx expo install expo-updates
```

##### EAS Update configured

To configure EAS Update, run:

```sh
eas update:configure
```

The above command adds the update URL and runtime version to **app.json**, and adds a [`channel`](/eas-update/deployment.md) field to each build profile in **eas.json**.

##### Preview build created

To receive PR preview updates, reviewers need a preview build with `expo-updates` and the EAS Update channel installed on their device. To create one:

```sh
eas build --profile preview --platform all
```

Since `expo-updates` is a native library, this build embeds both its native code and the channel from **eas.json**. Running the above command also allows EAS CLI to generate [credentials](/app-signing/app-credentials.md) the first time we trigger a preview build.

## The `build` job type for preview builds

Teams use preview builds for stakeholder testing. Members install the build through internal distribution onto their device/emulator/simulator. They do not have to run a development server or check out the branch to test changes.

```
Preview workflow pipeline: fingerprint checks native changes, get-build checks for existing builds, then creates a new preview build with Slack notification.
```

Like [development builds](/tutorial/cicd/development-builds.md#skip-unnecessary-builds-with-fingerprints), we add fingerprints to avoid unnecessary rebuilds when native code doesn't change.

### Add a preview.yml

Inside **.eas/workflows/**, let's add a new file called **preview.yml**. This workflow file uses the `preview` profile.

```yaml
name: Preview builds

jobs:
  fingerprint:
    name: Fingerprint
    type: fingerprint
    environment: preview
  get_android_build:
    name: Check for existing Android build
    needs: [fingerprint]
    type: get-build
    params:
      fingerprint_hash: ${{ needs.fingerprint.outputs.android_fingerprint_hash }}
      profile: preview
  get_ios_build:
    name: Check for existing iOS build
    needs: [fingerprint]
    type: get-build
    params:
      fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}
      profile: preview
  build_android:
    name: Build Android
    needs: [get_android_build]
    if: ${{ !needs.get_android_build.outputs.build_id }}
    type: build
    params:
      platform: android
      profile: preview
  build_ios:
    name: Build iOS
    needs: [get_ios_build]
    if: ${{ !needs.get_ios_build.outputs.build_id }}
    type: build
    params:
      platform: ios
      profile: preview
```

### Run the workflow

Run the workflow manually using the following command:

```sh
eas workflow:run .eas/workflows/preview.yml
```

In the EAS dashboard, notice that the workflow follows the same fingerprint pattern we implemented for [development builds](/tutorial/cicd/development-builds.md#skip-unnecessary-builds-with-fingerprints). Since we are creating the preview build for the first time, it runs the build jobs for Android and iOS. If we push another commit to the `main` branch without changing native code, the workflow skips the build jobs since compatible builds already exist.

## Slack notifications

> This section is optional. Not using Slack? Skip to the next section about PR previews.

Many teams use Slack for build notifications so their team sees build status without checking the EAS dashboard. When a build completes (or skips), the [`slack`](/eas/workflows/pre-packaged-jobs.md#slack) pre-packaged job posts the status to a channel.

### Create a Slack webhook URL

To send messages from EAS Workflows to our Slack channel, we need a webhook URL from Slack's settings:

1.  Go to [api.slack.com/apps](https://api.slack.com/apps) and create a new Slack app (or use an existing one).
2.  Under **Features**, select **Incoming Webhooks** and toggle it on.
3.  Click **Add New Webhook** and select the channel to publish notifications.
4.  Copy the webhook URL. It looks like: `https://hooks.slack.com/services/TD000/B000/XXXXXXXXXX`
5.  Add the webhook URL as an EAS environment variable named `SLACK_WEBHOOK_URL`. Open our project's [Environment variables](https://expo.dev/accounts/%5Baccount%5D/projects/%5Bproject%5D/environment-variables) page on the EAS dashboard, create the variable for the `preview` environment, and set its [visibility](/eas/environment-variables.md#visibility-settings-for-environment-variables) to **secret** since only EAS servers need to read it. Alternatively, create it with [EAS CLI](/eas/environment-variables/manage.md):

```sh
eas env:create --name SLACK_WEBHOOK_URL --value https://hooks.slack.com/services/TD000/B000/XXXXXXXXXX --environment preview --visibility secret
```

### Add a Slack notification job

Let's update **preview.yml** to add a `notify` job after the build jobs. The `notify` job uses `webhook_url` and `message` parameters, or a `payload` parameter for rich formatting with [Slack Block Kit](https://docs.slack.dev/block-kit). The job reads the webhook URL from the [`SLACK_WEBHOOK_URL` environment variable we created earlier](/tutorial/cicd/preview-builds.md#create-a-slack-webhook-url) through its `environment` field. Jobs default to the `production` environment, so setting `environment: preview` here is what makes the variable available.

```yaml
name: Preview builds

jobs:
  fingerprint: # ...
  get_android_build: # ...
  get_ios_build: # ...
  build_android: # ...
  build_ios: # ...
  notify:
    name: Notify on Slack
    after: [build_android, build_ios]
    type: slack
    environment: preview
    params:
      webhook_url: ${{ env.SLACK_WEBHOOK_URL }}
      message: 'Preview builds are ready - Android: ${{ after.build_android.status }}, iOS: ${{ after.build_ios.status }}'
```

The `after` field ensures the notification fires once the builds finish, regardless of the outcome. The `message` uses `${{ after.build_android.status }}` and `${{ after.build_ios.status }}` to include each platform's outcome (success, failure, or skipped). The team sees what happened without leaving Slack.

### Run the workflow

Run the workflow manually using the following command:

```sh
eas workflow:run .eas/workflows/preview.yml
```

On the EAS dashboard, we can verify that the `Notify on Slack` job runs successfully.

We can also verify this in the Slack channel integrated with the app.

## PR previews using EAS Update

A PR reviewer can read the diff, but cannot see the changes visually or test them on a device.

Web teams solve this with deploy previews. When someone opens a pull request, a CI/CD workflow generates a preview link. Reviewers open the link and test the changes without checking out the branch.

For mobile, we can set up the equivalent using [EAS Update](/eas-update/introduction.md). It delivers a JavaScript bundle to devices that already have a compatible build installed, skipping the native compilation step. For PR previews, an update is the right fit because reviewers can open and test quickly, then leave feedback on the PR.

EAS Workflows provides a [`github-comment`](/eas/workflows/pre-packaged-jobs.md#github-comment) pre-packaged job for this. It posts a comment on the pull request after the update publishes, giving reviewers a link or QR code to open the update on their device.

### Create a pr-preview.yml

Inside **.eas/workflows/**, let's add a new file called **pr-preview.yml**. This workflow runs when a pull request is created using the `on.pull_request` trigger. It only publishes an update using the `update` job type and then posts a comment on the PR with the link to the update.

```yaml
name: PR Preview

on:
  pull_request:
    branches: ['*']

jobs:
  publish_preview:
    name: Publish PR preview update
    type: update
    environment: preview
    params:
      channel: preview
  comment:
    needs: [publish_preview]
    type: github-comment
```

> Before testing the above workflow, commit **pr-preview.yml** and push it to the `main` branch of our GitHub repository. **EAS Workflows reads workflow files from the default branch.**

### Test with a pull request

Let's test the workflow by creating a pull request in our GitHub repository. A pull request requires a separate branch from `main`. Run the following command to create and switch to a new branch:

```sh
git checkout -b test-preview
```

Now, let's make a visible change in the Expo project (for example, change a text string or background color). Then, commit and push the branch:

```sh
git add .
git commit -m "Test PR preview"
git push origin test-preview
```

Open a pull request from `test-preview` to `main` on GitHub. The workflow runs automatically after we have created a pull request. On the EAS dashboard, we can verify that the `publish_preview` job runs first and the `comment` job runs after it succeeds.

On the GitHub pull request, a comment should appear with a link or QR code to test the update on a device.

Using the link or QR code in the comment, we can now open the update on our device or emulator/simulator and test the changes.

## Summary

Chapter 3: Preview builds

We created a preview build workflow with fingerprinting, added Slack notifications for build status, and set up PR previews using EAS Update so reviewers can test changes without checking out a branch.

In the next chapter, learn how to run end-to-end tests with Maestro in an EAS Workflows job.

[Next: Chapter 4: E2E tests](/tutorial/cicd/e2e-tests.md)
