Installation
Choose Your Project Type
Bundle Drop supports Expo SDK 54–57 and bare React Native 0.71+ on iOS and Android. The CLI detects the project type and applies the matching setup while preserving your existing configuration.
If you use Expo, read the dedicated Expo guide for managed/CNG builds, Release behavior, runtime authority, and strict fingerprint checks.
Compatibility
| Surface | Supported versions |
|---|---|
| Expo | SDK 54–57 |
| Bare React Native | 0.71+ |
| Platforms | iOS and Android |
| Architecture | Old and New Architecture |
| Node.js | 20.19.4+ |
Install the Package
For Expo projects, let Expo select a compatible package version:
npx expo install @gfean/react-native-bundle-dropFor bare React Native projects, install with npm or Yarn, then update iOS pods:
npm install @gfean/react-native-bundle-drop
cd ios && pod install && cd ..Authenticate and Complete Setup
Before setup, create an organization and project in Bundle Drop. If you have not done that yet, start with Project Creation.
Run the interactive login from your app directory:
npx bundle-drop loginlogin authenticates the CLI, creates bundle.drop.config.js, detects Expo or bare React Native, previews the complete setup plan, and asks before applying changes. It also creates backups for files it changes and synchronizes the project's runtime-delivery trust configuration.
After setup, verify the project:
npx bundle-drop doctorUse init when you want to rerun setup or need a non-interactive token flow:
npx bundle-drop init
npx bundle-drop init --project-type expo
npx bundle-drop init --project-type bare
npx bundle-drop init --token bdp_pat_xxxThe normal setup is intentionally unified. Expo projects receive the config plugin and Expo-preserving Metro wrapper. Bare projects receive the Metro config alias and the appropriate Release bundle resolver for their existing Android and iOS entrypoint shapes. There are no separate Metro or native initialization commands.
If you prefer not to use AI-assisted setup, or if guided setup stops because your project has a customized or ambiguous native entrypoint, use Manual Setup. It covers the current Kotlin ReactHost shape without recreating ReactNativeHost, existing legacy Kotlin and Java hosts, Swift and Objective-C app delegates, and Expo configuration.
Project Config
The CLI creates bundle.drop.config.js. The default runtime model is shared by Expo and bare React Native:
module.exports = {
projectType: "bare",
serverUrl: "https://api.bundledrop.app",
defaultChannel: "develop",
runtimeVersion: {
ios: "1.0.0",
android: "1.0.0",
},
org: { slug: "your-org-slug" },
project: {
name: "Your App Name",
slug: "your-app-slug",
apiKey: "your-project-api-key",
},
};Keep a platform runtime value unchanged for JavaScript and asset updates that remain compatible with the installed binary. Bump that platform's runtime and rebuild when native compatibility changes. See Runtime Version for the complete rule.
Existing bare projects without projectType remain supported. New configs include it so project detection stays explicit.
Commit bundle.drop.config.js. Its project identity and project.apiKey are public app configuration that must be available to local builds, CI, and the installed app. The project API key is not a Personal Access Token or private signing key. Keep CLI authentication files, Personal Access Tokens, and other private credentials out of source control.
Pin the Runtime Delivery Bootstrap
During login or init, setup writes .bundle-drop/runtime-delivery.lock.json. The lockfile is pinned build input, not a disposable cache. It tells the installed native runtime which manifest origin and public P-256 keys it may trust.
The bootstrap is safe and required to commit. It contains project identity, a manifest access identifier, and public verification keys. It does not contain a private signing key, Personal Access Token, or temporary bundle download capability.
Refresh and verify it from the app directory:
npx bundle-drop sync
git add bundle.drop.config.js .bundle-drop/runtime-delivery.lock.json .gitignore
npx bundle-drop doctorThe CLI updates .gitignore so generated .bundle-drop artifacts stay ignored while this exact lockfile remains tracked. Do not hand-edit or copy the lockfile between projects. Run bundle-drop sync whenever the project identity or trusted public keys change, commit the result, and create a new native binary from it. If the file or its .bundle-drop directory is accidentally deleted, sync safely recreates it and repairs the matching .gitignore rules. Use npx bundle-drop sync --dry-run to validate the project state without writing.
Projects with the former .bundle-drop/runtime-delivery.generated.json filename remain readable after upgrading. Run npx bundle-drop sync to validate and write the new lockfile, remove the legacy file safely, and repair .gitignore; then run npx bundle-drop doctor to confirm the migration.
Setup backups under .bundledrop-backup/ are different: they are local recovery material, not runtime input. Do not commit them. Keep them until setup, bundle-drop doctor, and a native build have succeeded, then remove them locally when you no longer need rollback assistance. Cleaning those backups must not remove .bundle-drop/runtime-delivery.lock.json.
Bare React Native Integration
The setup plan preserves the native host style already used by your app:
- Modern Kotlin
ReactHostapps keep the directReactHostshape and receive a Release-only Bundle Drop bundle path. - Existing Kotlin or Java
ReactNativeHostapps receive the matchinggetJSBundleFile()integration. - Swift, Objective-C, and Objective-C++ app delegates receive the matching Release bundle resolver.
- Debug builds continue to use Metro.
If your native entrypoints are highly customized and the CLI cannot produce a safe plan, it stops without guessing. Follow Manual Setup, preserve the existing host and fallback behavior, and run npx bundle-drop doctor again.
Initialize Bundle Drop in JavaScript
Call BundleDrop.init once, early in application startup. For a conventional React Native entrypoint, initialize before registering the root component:
import { AppRegistry } from "react-native";
import { BundleDrop } from "@gfean/react-native-bundle-drop";
import App from "./App";
import { name as appName } from "./app.json";
BundleDrop.init({
enabled: !__DEV__,
environment: __DEV__ ? "development" : "production",
channelName: "develop",
policy: "on-next-launch",
});
AppRegistry.registerComponent(appName, () => App);Expo Router apps should initialize in app/_layout.tsx; see Expo.
Build the Native App
Setup changes native integration, so create and install a new native binary before testing OTA behavior. Bare projects use their normal Release build process. Expo managed/CNG projects apply the plugin through prebuild, expo run:*, or EAS Build.
Expo Go and Debug/development-client builds keep Bundle Drop OTA disabled so Metro remains the development source. Test cold-start OTA behavior with a non-Debug/Release build.
Related Docs
- For Expo setup and strict fingerprint policy, see Expo.
- For a guided-setup fallback, see Manual Setup.
- For startup policies and initialization, see BundleDrop.init.
- For compatibility boundaries, see Runtime Version.
- For publishing your first update, see Uploading.
