Expo Development Builds and Update Compatibility
An Expo update must fit the native runtime installed in the app. A change that needs new native code requires a compatible new build; publishing JavaScript cannot add a missing native module to an existing binary. Manage runtime identity, platform, release targeting and device validation together.
Treat a development build as a way to test the project's native environment, not proof that every installed release can load the next update. Know which binaries are in the field and which update contract each expects. A label is useful only when the build and release process maintain its meaning.
TL;DR
- An Expo update must fit the native runtime in the installed app; JavaScript can't add a missing native module to an existing binary.
- Native changes need a new build and a new runtime version.
- Manage runtime identity, platform, release targeting, and device validation together.
- Know which binaries are in the field and which update contract each expects.
- Test older installed builds and the rollback path, not just the latest development build.
Quick Example
This JavaScript predicate checks two labels in fictional objects. It is not Expo's update-selection implementation and does not import an Expo SDK. It ran in Node, without a device, build or update service.
The fixture rejects a different runtime label and a different platform. It cannot discover whether two equal labels describe genuinely compatible native code. That depends on the real build, dependencies and update process. No native dependency was installed, and no update, staged rollout or rollback was performed.
Core Concepts
Native capability lives in the installed build
Expo's runtime-version guide explains that updates must be compatible with a build's native code and that native changes require a new build. It gives a missing-native-library example where reusing an old runtime label can cause an incompatible update to be attempted. Runtime versions
Inventory native dependencies and configuration changes before deciding whether an update can target an existing build. The relevant change may be a library addition, configuration plugin, SDK transition or another native-runtime input. A JavaScript-only diff in one folder does not by itself establish that the complete native environment is unchanged.
Development and release validation differ
Expo documents development builds as a project-specific development path with native capabilities and development tooling. Use the actual project build to test required integration instead of assuming a generic development client contains every needed native module. Development builds
Then validate the intended release binary and update configuration. Development conveniences, local servers and test credentials can differ from a shipped app's environment. A feature working during development is useful evidence for that path, not automatic evidence for over-the-air delivery to existing installations.
This is a proposed release-review matrix. The Node label predicate exercises none of the actual delivery or device behavior.
A runtime policy needs process ownership
Expo describes policies such as fingerprinting and manual runtime changes. The correct choice depends on how the project produces native builds and reviews changes. A policy can reduce manual mistakes, but it should be verified with representative native-affecting changes rather than treated as a universal compatibility proof.
Record which build artifact, source revision, dependencies and runtime identity produced the installed app. Retain enough release metadata to identify the population eligible for an update. Without that mapping, a matching string is difficult to interpret when an incident affects only part of the installed base.
Recovery cannot rewind every effect
The runtime guide discusses gradual rollout and error-recovery behavior. Test the actual recovery branch for the project's configuration and devices. Do not promise that every update failure will automatically return every device to a working state under all conditions.
Consider local data, server APIs and irreversible external effects separately. A JavaScript rollback can restore earlier code while data has already changed. Define which versions can read the resulting state and whether a forward fix is safer than returning to an older update.
Best Practices
Maintain a build/update compatibility record. Include platform, native dependencies, runtime policy, channel or branch targeting, environment configuration and verification evidence. Keep credentials out of the record while preserving the identity of the approved secret/configuration source.
Test representative installed binaries with the intended update. Include launch, important native integrations, offline behavior, API compatibility, local-data transitions and recovery. If multiple supported runtime populations exist, exercise the relevant combinations rather than testing only the newest development build.
Stage exposure with explicit success and stop criteria. Choose a population and observation window that can expose meaningful behavior, and account for delayed adoption. An absence of immediate crash reports does not prove that all devices have received or exercised the update.
Verify the actual targeting before publication through the organization's release process. A channel name is not a sufficient safety boundary if its mapping or runtime configuration is misunderstood. This article performs no publication and asserts no live channel state.
Use a new native build when the installed runtime cannot support the change. Trying to preserve an old label to avoid build distribution can merely conceal the incompatibility. Reverse an update-only plan when native or data-contract evidence shows that a new binary or migration is required.
After an incident, preserve the affected build/update identities and observed failure path. Compare expected eligibility with actual installation behavior. The goal is to correct the build-to-update contract, not just rename a version until one device starts working.
Common Mistakes
Shipping native code over the air
Reusing a runtime version after a native change
Testing only the latest development build
Treating a rollback action as recovery
FAQ
Do matching runtime strings prove compatibility?
No. The process must ensure the strings represent compatible native inputs. The toy checks labels only and cannot inspect a real binary.
How do I test update compatibility before a release?
Build the binaries your users actually have, publish the update to a staging channel with the same runtime version, and install it on real devices for each platform. Then test rollout targeting and rollback, because a compatibility check alone can't show what a device will load.
When is a new build needed?
When the change requires native capability or configuration absent from the installed binary. Review the complete native runtime and the project's chosen policy rather than relying on one JavaScript diff.