# How to Set Up Expo Application Services (EAS) Workflows: A Complete Guide

> Learn how to set up Expo Application Services EAS workflows for automated CI/CD and deployments. Automate builds and submissions for your Expo apps with this complete guide.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: how-to-guide
- Published: 2026-06-07

---

**Expo Application Services (EAS) workflows automate CI/CD pipelines for Expo apps through YAML definitions stored in `.eas/workflows/` that trigger builds, submissions, and deployments based on GitHub events.**

The openai/plugins repository provides production-ready patterns for configuring EAS workflows, offering a unified platform to build, submit, and update both web and native applications. By defining workflows in the `.eas/workflows/` directory, teams can create automated pipelines that respond to pushes, pull requests, and tags while maintaining separation of concerns across different deployment stages.

## Understanding EAS Workflow Architecture

EAS workflows are defined in YAML files located in the `.eas/workflows/` directory at the root of your project. Each workflow consists of one or more **jobs**, where the `type` field determines the specific action EAS executes.

The five primary job types supported in the openai/plugins implementation are:

| Job type | Description |
|----------|-------------|
| `build` | Compiles iOS or Android binaries using specified profiles from [`eas.json`](https://github.com/openai/plugins/blob/main/eas.json) |
| `submit` | Uploads completed binaries to the Apple App Store or Google Play Store |
| `update` | Publishes over-the-air (OTA) updates to existing native builds |
| `deploy` | Ships web bundles to hosting providers like Vercel or Netlify |
| `run` | Executes arbitrary shell commands for custom logic or validation |

According to the source code in [[`plugins/expo/skills/expo-deployment/references/workflows.md`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/references/workflows.md)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/references/workflows.md), jobs can depend on one another using the `needs` field, and conditional execution is supported via `if` expressions that reference previous job outputs.

## Configuring Triggers, Dependencies, and Conditions

Workflows respond to standard GitHub Actions events including `push`, `pull_request`, `schedule`, and manual `workflow_dispatch` triggers. This integration allows your **EAS workflow** to react immediately to code changes while maintaining fine-grained control over execution flow.

**Dependency chains** ensure sequential execution where required. For example, app store submissions must wait for native builds to complete. The `needs` array establishes these relationships, while the `if` field enables conditional logic—such as checking whether specific files changed before launching expensive build processes.

## Production Workflow Examples

The openai/plugins repository contains canonical implementations for common deployment scenarios. Below are the primary patterns you can adapt for your project.

### Deploy Web on Push to Main

Create [`.eas/workflows/deploy.yml`](https://github.com/openai/plugins/blob/main/.eas/workflows/deploy.yml) to automatically deploy your web bundle when changes merge to the main branch:

```yaml
name: Deploy
on:
  push:
    branches:
      - main
jobs:
  deploy_web:
    type: deploy
    params:
      prod: true

```

### Create PR Previews for Web

For web-based pull request previews, use [`.eas/workflows/pr-preview.yml`](https://github.com/openai/plugins/blob/main/.eas/workflows/pr-preview.yml):

```yaml
name: Web PR Preview
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  preview:
    type: deploy
    params:
      prod: false

```

### Publish OTA Updates for Native PRs

To distribute over-the-air updates for native app preview testing:

```yaml
name: PR Preview
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  publish:
    type: update
    params:
      branch: "pr-${{ github.event.pull_request.number }}"
      message: "PR #${{ github.event.pull_request.number }}"

```

### Full Production Release Pipeline

For complete iOS and Android releases triggered by version tags, create [`.eas/workflows/release.yml`](https://github.com/openai/plugins/blob/main/.eas/workflows/release.yml):

```yaml
name: Release
on:
  push:
    tags: ['v*']
jobs:
  build-ios:
    type: build
    params:
      platform: ios
      profile: production
  build-android:
    type: build
    params:
      platform: android
      profile: production
  submit-ios:
    type: submit
    needs: [build-ios]
    params:
      platform: ios
      profile: production
  submit-android:
    type: submit
    needs: [build-android]
    params:
      platform: android
      profile: production

```

### Conditional Builds to Save CI Minutes

Prevent unnecessary builds by checking for relevant file changes first, as implemented in [[`plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js) and related examples:

```yaml
name: Conditional Release
on:
  push:
    branches: [main]
jobs:
  check-changes:
    type: run
    params:
      command: |
        if git diff --name-only HEAD~1 | grep -q "^src/"; then
          echo "has_changes=true" >> $GITHUB_OUTPUT
        fi
  build:
    type: build
    needs: [check-changes]
    if: needs.check-changes.outputs.has_changes == 'true'
    params:
      platform: all
      profile: production

```

## Essential Configuration Patterns

### Profile-Driven Builds

**EAS workflows** rely on build profiles defined in your [`eas.json`](https://github.com/openai/plugins/blob/main/eas.json) file. The `params.profile` field selects which configuration to use, allowing distinct settings for development, preview, and production environments. Production releases typically specify `profile: production`, while feature branch testing uses `preview` or custom profiles.

### Branch and Tag Filtering

Limit workflow execution to specific Git references using the `on.push.branches` or `on.push.tags` selectors. Restricting releases to `main`, `release/*` branches, or `v*` tag patterns prevents accidental production deployments from feature branches.

### Securing Secrets with EAS Secrets

Sensitive values such as API keys for app store authentication or deployment webhooks must never appear in YAML files. Instead, store these in **EAS Secrets** and reference them within your workflow jobs. The [[`plugins/expo/skills/expo-deployment/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/SKILL.md)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/SKILL.md) documentation emphasizes this security pattern for production deployments.

## Key Files in the openai/plugins Repository

| File | Purpose |
|------|---------|
| [[`plugins/expo/skills/expo-deployment/references/workflows.md`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/references/workflows.md)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/references/workflows.md) | Complete syntax reference for EAS workflow definitions |
| [[`plugins/expo/skills/expo-deployment/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/SKILL.md)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-deployment/SKILL.md) | High-level overview of deployment strategies and best practices |
| [[`plugins/expo/skills/expo-cicd-workflows/scripts/package.json`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-cicd-workflows/scripts/package.json)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-cicd-workflows/scripts/package.json) | Dependencies for validating workflow YAML and EAS CLI integration |
| [[`plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js) | Utility script for fetching build artifacts in `run` jobs |
| [[`plugins/expo/skills/expo-api-routes/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-api-routes/SKILL.md)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-api-routes/SKILL.md) | Guidelines for serverless API routes callable from EAS jobs |

## Summary

- **EAS workflows** use YAML files in `.eas/workflows/` to define CI/CD pipelines for Expo applications
- **Five job types** handle distinct tasks: `build`, `submit`, `update`, `deploy`, and `run`
- **GitHub event triggers** initiate workflows on push, pull request, schedule, or manual dispatch
- **Dependency chains** via `needs` and conditional logic via `if` optimize execution flow and reduce CI costs
- **Profile-driven configuration** connects workflow parameters to [`eas.json`](https://github.com/openai/plugins/blob/main/eas.json) build profiles
- **Security best practices** require storing sensitive credentials in EAS Secrets rather than workflow files

## Frequently Asked Questions

### What is the difference between EAS Build and EAS Workflows?

**EAS Build** is a service that compiles native binaries, while **EAS Workflows** is a CI/CD platform that orchestrates multiple services including builds, submissions, and deployments. Workflows can trigger builds as one step within a larger pipeline that includes testing, OTA updates, and app store submissions.

### How do I trigger an EAS workflow manually?

Configure the `on.workflow_dispatch` event in your YAML file to enable manual triggers from the GitHub Actions tab. This is useful for emergency hotfixes or running ad-hoc deployment tasks without pushing code changes.

### Can I run custom scripts within EAS workflows?

Yes. Use the `run` job type with a `params.command` field to execute arbitrary shell commands. According to the [[`fetch.js`](https://github.com/openai/plugins/blob/main/fetch.js)](https://github.com/openai/plugins/blob/main/plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js) implementation in the openai/plugins repository, these scripts can interact with build artifacts, validate changes, or perform custom deployment logic.

### Where should I store API keys for app store submissions?

Store all sensitive credentials—including Apple App Store Connect API keys and Google Play service account JSON—in **EAS Secrets** rather than hard-coding them in workflow YAML files. Reference these secrets in your [`eas.json`](https://github.com/openai/plugins/blob/main/eas.json) profiles or workflow parameters to maintain security compliance.