new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Expo · EAS · all subjects

eas-update

216 notes in this subject, read out of this brain and free to use. This is page 1 of 4.

Configure code signing with CNG command

Run the command: npx expo-updates codesigning:configure --certificate-input-directory certs --key-input-directory ../keys. If using Continuous Native Generation (CNG), the app.json configuration changes are all that is needed and will be applied to native projects the next time they are generated.

Key rotation reasons

Key rotation is performed for three main reasons: key expiration (certificate validity ends), private key compromise (private key exposed publicly), or security best practices (periodic rotation). After key expiration, updates signed with the expired key will no longer be applied, though previously downloaded updates continue to function. A compromised key cannot guarantee update integrity.

Publish signed update command

Run: eas update --private-key-path ../keys/private-key.pem. The EAS CLI automatically detects code signing configuration and creates a digital signature using the private key. The signing process is performed locally so the private key never leaves the machine, and the generated signature is automatically sent to EAS.

Public key and certificate storage

The public key is not sensitive and may be stored alongside the private key. The code signing certificate should be included in the project and checked into source control. It contains the public key and a method for verifying code signatures.

Generate code signing key and certificate command

Run the command: npx expo-updates codesigning:generate --key-output-directory ../keys --certificate-output-directory certs --certificate-validity-duration-years 10 --certificate-common-name "Your Organization Name". This generates three files: ../keys/private-key.pem (the private key), ../keys/public-key.pem (the public key), and certs/certificate.pem (the code signing certificate).

Include message in EAS Update

CodePush CLI has a --description flag for including messages with updates. In EAS Update, you can achieve similar functionality using the extra field in your app config. Refer to the --message flag in the expo/UpdatesAPIDemo example.

Switch deployment at runtime in EAS Update

To switch the deployment being used at runtime in EAS Update (similar to CodePush's sync() function), use Updates.setUpdateURLAndRequestHeadersOverride(). This is documented in the Override update configuration at runtime guide.

EAS Update preview workflow

You can use EAS Update to achieve a web-like preview workflow. See the how to preview updates guide for details.

Branch promotion flow disadvantages

Disadvantages include: requires one channel per production runtime version to maintain historical updates for previous production releases, making runtime version policies more difficult to use. Requires bookkeeping of branch names and communication with team about which branches are currently pointed at test and production builds.

Branch promotion flow example channel and branch naming

Builds are created with channel names like 'production-rtv-1' to indicate the runtime version, and 'staging' for testing. Update branches are named like 'version-1' and 'version-2'. The 'staging' and 'production-rtv-1' channels are pointed at the appropriate update branches using the website or EAS CLI. When a new runtime version is needed, new builds are created with channels like 'production-rtv-2'.

Branch promotion flow runtime version requirements

The branch promotion flow requires manual specification of runtime versions and does not support automatic runtime version policies such as 'sdkVersion', 'appVersion', 'nativeVersion', and 'fingerprint'. Users must manually specify runtime versions when using this flow.

Branch promotion deployment flow overview

The branch promotion flow manages versioned releases using version-based update branches like 'version-1.0'. Builds are created per major version for production and separate builds for testing. Version-based update branches are dynamically mapped to channels to promote tested changes from testing to production. The flow uses expo-github-action to publish updates when merging to branches, with manual channel pointing to update branches via website or EAS CLI.

Custom expo-updates server as alternative to EAS Update

If your preferred release process is not supported by EAS Update, you can host your own update service compatible with the Expo Updates Protocol and point the expo-updates configuration to that service. The protocol only defines Runtime Version and Platform concepts, allowing you to create custom concepts on top, similar to how EAS Update built channels and branches.

Development builds can load updates from any channel

Development builds can load updates from any channel, provided the runtime version is compatible. This allows flexible preview and testing scenarios.

EAS Update concepts: channels, branches, and runtime versions

EAS Update provides channels to indicate which environment the update targets (such as 'production' or 'staging'), branches for Git integration and more complex workflows, and runtime versions to indicate which app version the update targets (such as '1.0.0' or '1.0.1'). For simple workflows, you can keep channels pointed at branches with the same name and mostly ignore branches.

Install expo-updates package

If expo-updates is not in package.json, install it using: npm: npx expo install expo-updates; yarn: yarn expo install expo-updates; pnpm: pnpm expo install expo-updates; bun: bun expo install expo-updates.

Inspect manifest via URL

To inspect a manifest, GET the URL from app.json updates.url (example: https://u.expo.dev/your-project-id) and add three query parameters: runtime-version, channel-name, and platform. Example: https://u.expo.dev/your-project-id?runtime-version=1.0.0&channel-name=production&platform=android. Going to this URL directly will show an error about a missing header, but adding the query parameters will display the manifest.

Use expo-dev-client for debugging updates

Create a development version of a build using expo-dev-client. This will help preview published updates inside a problematic build.

View network requests for debugging

To identify root cause of issues, inspect network requests the app is making to EAS servers. Use a program like Proxyman or Charles Proxy to watch requests. Follow the program's instructions for installing an SSL certificate to decode HTTPS requests. The requests of interest are from https://u.expo.dev (which returns update manifests) and https://assets.eascdn.net (which returns assets like images and fonts). Expect to see request headers: Expo-Runtime-Version (should match the runtime version of the build and update), expo-channel-name (should match the channel name in eas.json), and Expo-Platform (should be android or ios). Expect to see 200 response codes or 304 if nothing has changed.

Missing deployment indicates misconfiguration

If a deployment is not displayed, it means the build is not configured properly for EAS Update. To fix this, configure the channel, configure the runtime version, verify general configuration, and rebuild the app.

Enable expo-updates in debug builds with environment variable

By default, expo-updates is enabled only in release builds. To enable it in debug builds for testing, set the debug environment variable: export EX_UPDATES_NATIVE_DEBUG=1. This allows testing and debugging of native code in an environment closer to production without making a release build.

Missing updates in deployment

If the displayed deployment does not have any updates, an update must be published to the branch. If an update was already published, check the Updates page to make sure it matches the runtime version of the build.

Unexpected runtime version in deployment

If the deployment runtime version is unexpected, it means the build was not built with the correct runtime version. To fix this, configure the runtime version in app.json or app.config.js and rebuild the app.

Unexpected channel in deployment

If the deployment channel is unexpected, it means the build was not built with the correct channel. To fix this, configure the channel in eas.json and rebuild the app.

Monitoring update adoption via EAS dashboard

The details page for an update shows metrics for the number of users who have run the update, plus the number of failed installs. The deployments page includes a table and chart showing the number of users who have run each update related to a particular update channel and runtime version combination over a given time period.

Republish makes previous update immediately available

The republish command takes a previous update and publishes it again so it becomes the most current update on the branch. As users re-open their apps, they will see the newly re-published update and download it. This is similar to a Git reversion, where the correct commit is placed on top of the Git history.

Republish previous update command with branch name

Use the command 'eas update:republish --branch [branch-name]' to republish a previous update within a branch. This shows a list of recent updates on the branch and allows you to select the update group to republish. Example: 'eas update:republish --branch version-1.0'.

Republish previous update command with update group ID

Use the command 'eas update:republish --group [update-group-id]' to republish a previous update within a branch by its update group ID. Example: 'eas update:republish --group dbfd479f-d981-44ce-8774-f2fbcc386aa'.

Optimize bandwidth usage strategies

To optimize bandwidth usage: monitor usage metrics and identify unusual spikes or inefficiencies, optimize asset size by following the asset optimization guide, and use asset selection to reduce the number of assets included with each update (an advanced optimization).

Factors affecting bandwidth consumption

Actual bandwidth usage varies based on user behavior (not all users download every update; many skip intermediate updates when reopening the app) and missing assets (if an update includes fonts, images, or other assets not already on the device, they must be downloaded as well).

How to estimate update bandwidth size

To estimate bandwidth usage per update: identify the size of update assets not already on the device, then apply the compression ratio. For example, if JavaScript is 10 MB uncompressed and Hermes bytecode achieves a 2.6× compression ratio, the actual download size is approximately 3.85 MB.

Broken update recovery strategy: rollback considerations

When a broken update is published, the first thing to try is rolling back to an older update known to work. However, rollback may not be safe if the broken update modified persistent state (such as AsyncStorage or file system data) in a non-backwards-compatible way. Users should test rollback in a staging environment that closely emulates end user device state by loading the broken update and then rolling back.

Content appeared event distinction

expo-updates distinguishes between errors caught before and after the React Native native 'content appeared' event fires (ReactMarkerConstants.CONTENT_APPEARED on Android or RCTContentDidAppearNotification on iOS), which occurs approximately when the app's first view has rendered on screen for that update. This distinction is critical because if an error occurs before content has appeared, no persistent state modification code is assumed to have executed, making rollback safe.

Error recovery purpose and limitations

The error recovery flow in expo-updates is designed to prevent updates from bricking an app by ensuring the app has the opportunity to download a new update and fix itself. It is not a full safety net; users will still see crashes in many cases. The purpose is to prevent crashes on launch before the app can check for updates, making the app unusable until uninstalled and reinstalled.

iOS error stacktrace format

On iOS, when error recovery cannot recover, the stacktrace shows 'Last Exception Backtrace' and generally indicates an error originated in JavaScript, even though it appears thrown from expo-updates. The stacktrace includes references to EXUpdatesAppController and EXUpdatesErrorRecovery. However, Apple's crash reporting does not include the exception message detailing the underlying error and its JavaScript location, so reproducing the crash locally with Xcode debugger or macOS Console app may be necessary.

Android error stacktrace format

On Android, when an error recovery system cannot recover from a fatal JS error, it re-throws the original exception. The stacktrace shows 'AndroidRuntime: FATAL EXCEPTION: expo-updates-error-recovery' with the process name and will include 'com.facebook.react.common.JavascriptException'. The stacktrace of the original exception is preserved, and the underlying error information may be visible depending on the crash reporting service.

Fix forward strategy when rollback is unsafe

If no safe rollback update can be identified, the strategy is to fix it forward by publishing a new update with a fix as soon as possible (though not before being 100% confident in the fix). Even users who download the broken update should be able to download the fix through the error recovery mechanism, though they should take time to ensure the fix is solid.

Preview update URL format for development build

The URL format to open an EAS Update in a development build is: [slug]://expo-development-client/?url=[https://u.expo.dev/project-id]/group/[group-id]. Example: my-app://expo-development-client/?url=https://u.expo.dev/675cb1f0-fa3c-11e8-ac99-6374d9643cb2/group/47839bf2-9e01-467b-9378-4a978604ab11. Copy and paste this URL into the development build's launcher screen under Enter URL Manually, or create a QR code for the URL and scan it with your device's camera.

Platform property in builds

Every build has a platform, such as 'Android' or 'iOS'.

Update configuration is available

When the library checks for updates and when it downloads them, they are configurable via app config.

EAS Update with EAS Build recommended setup order

If planning to use EAS Update with EAS Build, follow the EAS Build setup guide first before setting up EAS Update. Alternatively, EAS Update can be used as a standalone service without other EAS services.

Testing updates after publication

After publishing an update, test it using: Extensions tab in a development build, Expo Orbit to install and launch the update, Updates API and app config to load updates programmatically, or manual testing by force closing and reopening a release build up to two times. Updates are automatically downloaded in the background when the app starts up and makes a request for new updates.

Prerequisites for EAS Update

EAS Update requires: an Expo account (free or paid plans available), a React Native project, Expo CLI and Expo Metro Config, and use of registerRootComponent instead of registerComponent (or registerApplication). Assets included in updates may not be available in release builds if registerRootComponent is not used.

Channel configuration in iOS native project

To configure update channels in Expo.plist without CNG, add EXUpdatesRequestHeaders key with a dictionary containing expo-channel-name key and the channel name as its value. The Expo.plist file must be added to the Xcode project.

Channel configuration in Android native project

To configure update channels in AndroidManifest.xml without CNG, add a meta-data entry with name expo.modules.updates.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY and android:value of {"expo-channel-name":"your-channel-name"}, replacing your-channel-name with the actual channel name.

iOS Expo.plist updates for EAS Update

When running eas update:configure on iOS projects without CNG, two entries are added to ios/project-name/Supporting/Expo.plist: EXUpdatesRuntimeVersion with value 1.0.0 (or similar), and EXUpdatesURL with value https://u.expo.dev/your-project-id. The Expo.plist file must be added to the Xcode project.

EAS setup version in GitHub Actions

The Setup EAS step should use expo/expo-github-action@v8 with eas-version: latest and pass the EXPO_TOKEN via the token parameter.

Setup Node GitHub Actions step for EAS workflow

The Setup Node step uses actions/setup-node@v6 and should include node-version: 24 and cache: yarn parameters.

Using Bun instead of Yarn in EAS Update workflow

To replace Yarn with Bun as the package manager, replace the 'Setup Node' step with 'Setup Bun' using 'uses: oven-sh/setup-bun@v1' with 'bun-version: latest'. Then replace the 'Install dependencies' step with 'run: bun install'.

Adding EXPO_TOKEN to GitHub repository secrets

Navigate to https://github.com/your-username/your-repo-name/settings/secrets/actions (replacing your-username and your-repo-name with your project's actual values). Under Repository secrets, click New repository secret. Create a secret named 'EXPO_TOKEN' and paste the personal access token as the value.

Creating EXPO_TOKEN personal access token

To set up EXPO_TOKEN for GitHub Actions, navigate to https://expo.dev/settings/access-tokens, click Create token to generate a new personal access token, and copy the generated token.

expo-github-action versions

The workflow uses expo/expo-github-action@v8 for the main setup and expo/expo-github-action/preview@v8 for the preview subaction.

Node.js version for EAS Update workflow

The GitHub Actions workflow should use Node.js version 24 with Yarn as the package manager, configured with the actions/setup-node@v6 action.

EXPO_TOKEN validation in GitHub Actions

The workflow must check for the presence of the EXPO_TOKEN secret at the beginning of the job. If the token is missing, the workflow should exit with status code 1 and display an error message.

Permissions required for GitHub Actions EAS workflow

The GitHub Actions workflow job requires the 'permissions' section to enable adding comments to pull requests. The required permissions are 'contents: read' and 'pull-requests: write'.

Checkout action version in EAS workflow

The workflow uses actions/checkout@v5 for checking out the repository.

Rebuild native code after migration

After configuring EAS Update, you must create new builds because the changes affect the native code layer inside builds. Once your builds are complete, you can start publishing updates.

Constants.manifest now returns null

Constants.manifest will now always return null after migrating to EAS Update. Access most properties using Constants.expoConfig from the expo-constants library instead.

Monthly active user billing for EAS Update

A monthly active user equals one unique installation of an app that downloads at least one update during a billing cycle. An app install downloading updates daily counts as 1 user. An install with no new updates counts as 0 users. Uninstalling and reinstalling counts as 2 users. A single device with two apps from one account is 2 users.

Image assets location and viewing

App users will download any new images or other assets when they detect a new update if those assets are not already part of their build. All assets uploaded to EAS servers are in dist/assets. The assets there are hashed with their extensions removed. To see a pretty-printed list of assets, run: npx expo export (or yarn expo export, pnpm expo export, or bun expo export depending on package manager).

Give your agent this brain