Choose the SDK for your framework
The walkthrough below uses React Native and Expo. NativeScript has a separate alpha integration with its own native startup hook and activation rules.
React Native & Expo
Use @nitropush/react-native. Expo uses the config plugin; bare React Native uses the native bundle resolver.
NativeScript · Alpha
Use @nitropush/nativescript for signed application-tree updates, assets, and file deltas. Signing is required and updates activate on a cold restart. Start in a dedicated test environment; the guide covers package availability, supported builds, and limitations.
The two release lanes
React Native applications contain native code and a JavaScript bundle. NitroPush updates the JavaScript bundle and compatible assets without replacing the signed iOS or Android binary. Changes to Swift, Kotlin, permissions, native modules, entitlements, or the app’s core purpose still require a new App Store or Google Play release.
Native release lane
Use the stores for native dependencies, operating-system permissions, runtime compatibility changes, and new binary versions.
OTA release lane
Use NitroPush for compatible JavaScript, TypeScript, UI, business-logic, copy, and asset fixes between native releases.
1. Install the runtime once
Add @nitropush/react-native to the app. Expo projects use the NitroPush config plugin; bare React Native projects wire the native bundle resolver into AppDelegate and MainApplication. Debug builds continue to use Metro, while release builds can load the active verified OTA bundle.
The deployment key belongs in the native configuration—not a public JavaScript environment variable. It identifies the project environment the binary is allowed to query.
2. Configure before React renders
The hosted setup uses the no-argument configure() function at module scope. After the first successful render, notifyAppReady() confirms that the active bundle is healthy. A later sync() call checks for and installs a compatible release.
import { configure, sync, InstallMode } from '@nitropush/react-native';
import { useEffect } from 'react';
// Module scope: initialize before React renders.
const client = configure();
export function App() {
useEffect(() => {
client.notifyAppReady();
sync(client, { installMode: InstallMode.ON_NEXT_RESUME });
}, []);
return null;
}notifyAppReady() runs. If the next launch finds an unconfirmed bundle, NitroPush restores the previous known-good version.3. Build and upload a release
The CLI accepts Expo export directories and CodePush-style Hermes or JavaScript bundles. It determines the artifact kind, computes SHA-256 checksums, uploads the required bytes, and creates a release scoped to a project and environment.
nitropush release upload \
--project <project-id> \
--environment prod \
--runtime-version 1.2.3 \
--label 1.2.4 \
--bundle-path ./dist--runtime-version protects runtime compatibility: a release for one native app version is not blindly offered to another. Test, stage, and production use separate environments and deployment keys.
4. Sign before the upload leaves CI
Projects can register an ECDSA P-256 public key. The private key stays with your team and signs the bundle during upload. Devices verify the signature before activation, so a modified or unsigned payload is rejected. Keep the private PEM in a secret manager and pass its temporary file path with --signing-key.
5. Route the right release to the right device
When the SDK checks for an update, NitroPush evaluates the deployment key, platform, app version, release status, and rollout bucket. A production device cannot accidentally receive a staging release, and percentage rollouts use a stable device identity so a device remains in the same bucket.
- The application calls
sync()on foreground, on demand, or from your chosen lifecycle event. - The SDK requests the latest compatible release.
- NitroPush returns no update or a manifest for the matching full bundle or delta patch.
- The SDK downloads in the background and reports progress.
6. Download fewer bytes when a delta is available
With delta updates enabled, NitroPush can create a bsdiff patch between compatible bundles. A device reports the hash of its current bundle; the service returns a matching patch only when one exists and is meaningfully smaller. The complete bundle remains available for fresh installs, mismatched bases, and fallback.
After applying a patch, the SDK verifies the reconstructed bundle’s SHA-256 checksum and then verifies its cryptographic signature when signing is enabled.
7. Install on your schedule
Choose an install mode that matches the urgency and user experience: immediate activation, next restart, next resume, or next suspension. Normal updates can wait for a natural lifecycle boundary; critical JavaScript fixes can use a more urgent policy after testing.
8. Observe, expand, or recover
Download, install, failure, rollback, and device-activity events originate in the native SDK, including events that JavaScript cannot reliably report during a failed launch. Start with a limited rollout, observe the release, then increase the percentage. If a bundle fails before confirmation, the SDK restores the last known-good bundle on the next launch.
What NitroPush deliberately does not do
- It does not bypass store review for native code changes.
- It does not make an incompatible JavaScript/native API contract safe.
- It does not require production apps to load bundles in debug builds.
- It does not put your private bundle-signing key on NitroPush servers.
Continue with the React Native OTA update guide, compare the approach with CodePush and EAS Update, or follow the release documentation.