CLI tool
expo/expo-github-action avatar
expo/expo-github-action

expo-github-action: EAS builds and updates inside GitHub Actions

Expo GitHub Action makes it easy to automate EAS builds or updates

1,031 stars107 forksTypeScriptMIT

At a glance

What is it?
expo-github-action is the official Expo action that puts the Expo CLI and EAS CLI in a GitHub Actions job, handles authentication and caching, and adds a preview flow for pull requests. The judgment is that it is the shortest path to a working EAS pipeline, and the things to watch are the per job token setup and the version drift between the documented examples and the current release.
Who is it for?
Use expo-github-action if your app is on Expo and you want EAS Update or EAS Build running from a push without hand wiring CLI installation, authentication and caching in every job. Do not use it if your release pipeline is not on GitHub Actions, or if you cannot accept a token that has to be re-exported separately in each job, which is the pattern the action documents rather than hides.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the action puts into the job for you

The README states the value plainly: with this Expo action you get full access to the Expo CLI and the EAS CLI, which lets you automate the eas update or eas build commands and leaves you with more time to work on your project. The extra features it lists are caching and authentication, described as included to make usage as simple as possible.

That is a narrower description than it first appears. The action is not a deployment system of its own, and it does not know anything about your app. It prepares a runner so that the EAS CLI is present, the right Expo account is authenticated, and the tools are cached, and then your own run steps invoke eas build or eas update as ordinary commands.

Who it is for is anyone shipping an Expo app on GitHub and wanting the build or the over the air update to happen automatically on a push. The repository topics list continuous integration and continuous delivery, the description says it makes it easy to automate EAS builds or updates, and the package.json describes the package as Expo CLI in your GitHub Actions workflow. The code is TypeScript, the licence is MIT, and the repository is not archived.

Five inputs, all declared in action.yml

The action's configuration is a small table, and the README says it is customizable through variables defined in action.yml. The inputs are worth reading as a whole because they show exactly how much the action is doing on your behalf.

The eas-version input sets the EAS CLI version to install, and it is skipped when omitted, so leaving it out means no EAS CLI is installed for you. The eas-cache input controls whether the GitHub Actions cache is used, and it defaults to true, so caching is on unless you turn it off. The packager input chooses the package manager and defaults to yarn, with bun and npm given as the other examples. The token input carries the token of your Expo account and is documented to be used with secrets. The patch-watchers input defaults to true and controls whether the fs.inotify limits are patched on Ubuntu.

Two of those deserve a second look. A packager default of yarn means a project that uses npm has to set the input explicitly, otherwise the caching and installation steps will look for a yarn lockfile that is not there. And patch-watchers being on by default means the action modifies a kernel limit on the runner, which is convenient for the ENOSPC problem it addresses and worth knowing about if your runner image is hardened.

A first EAS update on every push to main

The workflow shape is short, and the trigger and the job skeleton come straight from the README example for creating a new EAS Update on push to main:

yaml
on:
  push:
    branches:
      - main
jobs:
  update:
    runs-on: ubuntu-latest
    steps:

The action step is where the toolchain is set up. The excerpt below omits the step name, which in the README carries an emoji:

yaml
        uses: expo/expo-github-action@v8
        with:
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}

Two things happen here. Passing eas-version: latest makes the action install the EAS CLI, and the README recommends latest for the EAS CLI. Passing the token authenticates the CLI, and the README is emphatic that you should always use secrets when using tokens.

After that, the remaining steps are yours. Dependencies are installed with your package manager:

yaml
        run: yarn install

and the update itself is a plain command with non interactive flags so the job does not stop for a prompt:

yaml
        run: eas update --auto --non-interactive

The build variant is identical except for the last step, which runs eas build --non-interactive. Once a workflow file like this exists in the repository, a push to main produces a published update without anyone opening a terminal.

Preview builds through the preview sub-action

The pull request workflow is the more interesting of the three examples, because it is the case the README justifies with a cost argument: reviewing a pull request takes time, since the reviewer has to check out the branch, install the changes and run the bundler, and the project can be published automatically so the reviewer skips those steps.

The preview job is a separate sub-action of the same repository, referenced by path:

yaml
        uses: expo/expo-github-action/preview@v8

and it takes a command rather than doing a build itself:

yaml
          command: eas update --auto --branch ${{ github.event.pull_request.head.ref }}

The inline comment in the README explains the detail that trips people up: github.event.pull_request.head.ref is only available on pull_request triggers, so on any other trigger you have to supply your own branch name or keep the automatically inferred one from --auto. The repository layout backs this up, with separate preview/, preview-build/ and preview-comment/ directories, which suggests the preview flow is more than a thin wrapper: there is code for building the preview and code for posting a comment about it.

The preview job also uses a different trigger, on: [pull_request], so it runs for every pull request rather than for pushes to main.

The token is exported per job and never stored

This is the caveat section of the README, and it is the one most likely to cost you an afternoon. Some Expo commands, such as expo publish and eas build, require authentication, and the action exports the token to make sure you are authenticated in every workflow step. The note underneath says this action does not store the token anywhere, and that each separate workflow job needs to set up the token individually.

The mechanism is therefore environment export, scoped to a job. It is not a global login, and it is not a credential store. Two consequences follow. If your workflow has a build job and a separate publish job, both need their own Setup EAS step with the token, or the second job fails on an unauthenticated command. And because the token travels as a step input, the action must appear in every job that touches EAS, which is exactly what the three examples show.

The caching section works the same way in spirit. You can opt out of caching the Expo and EAS CLI installations, and under the hood it uses the GitHub Actions cache, so the second run of a job reuses the downloaded CLI instead of fetching it again. The cache is keyed to the tool versions in play, which is another reason to pin eas-version deliberately rather than leaving it at latest.

Version 9.0.0 exists, but the examples still say v8

The release list shows 9.0.0 published on 2026-06-02, preceded by 8.2.1 from 2024-01-15 and 8.2.0 from 2023-12-02. The last push to the repository was on 2026-06-02 as well, so the most recent activity is the major bump, and there has been no commit since. The version in package.json matches the release, at 9.0.0, and the build output is bundled with ncc into the build/ directory that the action.yml points at, with the sources in src/ and the command handling in command/.

Here is the concrete wrinkle. Every workflow example in the README uses expo/expo-github-action@v8 and expo/expo-github-action/preview@v8, while the newest published release is 9.0.0. Copying an example verbatim therefore pins you to the previous major version, which is a defensible choice but not an obvious one, and the README does not explain what changed in the major bump. The CHANGELOG.md file is the place to look for that, and semantic-release is configured in the repository to write it, along with the .releaserc.js file.

The rest of the tooling suggests a serious internal setup: Jest with ts-jest and snapshot testing through prettier, ESLint with the universe config, and a bun.lock file alongside the TypeScript sources. That matters for one reason: this is infrastructure that many teams depend on, and a repository whose last activity is a single major release four months old is worth watching rather than assuming is moving.

Editorial conclusion

Use expo-github-action if your app is on Expo and you want EAS Update or EAS Build running from a push without hand wiring CLI installation, authentication and caching in every job. Do not use it if your release pipeline is not on GitHub Actions, or if you cannot accept a token that has to be re-exported separately in each job, which is the pattern the action documents rather than hides. Before you copy a workflow, check which major version you reference, because the README examples still use expo/expo-github-action@v8 while the latest published release is 9.0.0, then confirm the eas-version you pin and the EXPO_TOKEN secret name.

Frequently asked questions

How do I use expo-github-action to run an EAS build in GitHub Actions?

Add a step that uses expo/expo-github-action with an eas-version and a token, then run eas build --non-interactive in a following step. The token is the Expo account token, and the README says to pass it through GitHub secrets as EXPO_TOKEN.

Do I need to set the EXPO_TOKEN secret in every workflow job?

Yes. The README states that the action does not store the token anywhere and that each separate workflow job needs to set up the token individually, so every job that runs an authenticated EAS command needs its own setup step.

What is the difference between expo-github-action and running the EAS CLI directly in a run step?

The action installs the EAS CLI, exports the token so every step is authenticated, caches the Expo and EAS CLI installations through the GitHub Actions cache, and patches the fs.inotify limits on Ubuntu. It also ships a separate preview sub-action for pull requests that can publish a preview build and comment on the pull request.

Official sources

  1. expo/expo-github-action on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/expo-expo-github-action.svg)](https://hysenlabs.com/projects/expo-expo-github-action)

Was this useful?