Expo
Expo Support
Bundle Drop supports Expo SDK 54–57 on iOS and Android, including managed/CNG projects and projects with committed native directories. The Expo config plugin owns the native integration, while the Metro wrapper preserves Expo's existing bundler behavior.
Both the old and new React Native architectures are supported.
Install and Set Up
Install through Expo, then run the unified Bundle Drop setup:
npx expo install @gfean/react-native-bundle-drop
npx bundle-drop login
npx bundle-drop doctorlogin creates the project config, detects Expo, previews the changes, and asks before applying them. Expo setup registers @gfean/react-native-bundle-drop as a config plugin, wraps the existing Expo Metro config, and preserves unrelated plugins and Metro behavior.
To rerun setup explicitly:
npx bundle-drop init --project-type expoIf native directories already exist, setup can preview a layered Expo prebuild so generated native integration stays aligned with app.json or app.config.*. Managed/CNG projects can keep ios and android absent until the next native build.
Initialize with Expo Router
Call BundleDrop.init once in the root layout, before rendering the application tree:
import { BundleDrop } from "@gfean/react-native-bundle-drop";
import { Stack } from "expo-router";
BundleDrop.init({
enabled: !__DEV__,
environment: __DEV__ ? "development" : "production",
channelName: "develop",
policy: "on-next-launch",
});
export default function RootLayout() {
return <Stack />;
}If your Expo app uses a conventional entrypoint instead of Expo Router, initialize before AppRegistry.registerComponent, as shown in Installation.
Development and Release Builds
Expo Go can run the app with Bundle Drop disabled because Expo Go does not contain the Bundle Drop native adapter. Debug and development-client builds also keep Metro in control. This makes normal development and debugging behave as expected, but those builds do not exercise Release cold-start OTA loading.
Use a non-Debug/Release native build to test OTA behavior:
npx expo run:ios --configuration Release
npx expo run:android --variant releaseFor EAS Build, use your normal build profiles after setup:
eas build --platform ios
eas build --platform androidConfig plugin changes take effect in the next native generation or build. Rebuild whenever you add or remove native dependencies, change native plugins, switch JavaScript engines or architectures, or make another native compatibility change.
Default Runtime Authority
By default, Bundle Drop uses literal runtime versions from bundle.drop.config.js:
module.exports = {
projectType: "expo",
runtimeVersion: {
ios: "1.0.0",
android: "1.0.0",
},
// serverUrl, org, and project are generated during login
};This is the same runtime model used by bare React Native. Keep the value unchanged for compatible JavaScript and asset updates. When a native change affects one platform, bump that platform's value and rebuild it. Uploads in this mode do not require Expo build receipts or compare fingerprints.
Strict Expo Fingerprint Authority
If you want every upload tied to the exact Expo native build identity, opt into Expo runtime authority:
module.exports = {
projectType: "expo",
runtimeVersion: { source: "expo" },
// serverUrl, org, and project are generated during login
};In strict mode, Bundle Drop resolves the Expo runtime policy and native fingerprint, records the identity of the built binary, and rejects an upload when its resolved identity does not match that build. This prevents an OTA bundle from being published against incompatible native inputs.
Strict mode also requires a clean Git worktree before a layered prebuild when native directories are committed. That check applies only to this opt-in authority mode; the default literal runtime flow does not require fingerprint receipts.
For a local Release build, build the exact source you intend to upload from and keep the generated receipt. For EAS Build, import the matching receipt before upload:
npx bundle-drop eas-receipt ios --build-id <eas-build-id>
npx bundle-drop upload ios --channel develop --build-receipt <receipt-path>Use strict mode when exact Expo build identity enforcement is part of your release policy. Use literal runtime versions when your team deliberately owns the compatibility boundary and wants the same workflow across Expo and bare React Native.
Upload Expo Updates
Expo uploads resolve app and runtime identity from the project configuration, so the normal commands do not need bare React Native version flags:
npx bundle-drop upload ios --channel develop
npx bundle-drop upload android --channel developThe installed native binary and uploaded bundle must still share the same runtime version. See Runtime Version before changing native dependencies or build configuration.
Expo Updates Ownership
Bundle Drop and expo-updates both control which JavaScript bundle loads at native startup. Do not leave both active.
If the project currently uses expo-updates, run the explicit migration and review the proposed changes:
npx bundle-drop init --project-type expo --migrate-expo-updatesRebuild the native app after the migration. Existing EAS Build infrastructure remains usable; the conflict is specifically the runtime update layer inside the app.
Verify the Integration
Run diagnostics after setup and after native-affecting configuration changes:
npx bundle-drop doctor --project-type expoDoctor verifies the config plugin, Metro wrapper, native integration when generated directories exist, runtime authority, and platform build identity.
