Implementing Hot Code Push for React Native Apps (CodePush)
App Store Review can take from several hours to several days. When there's a critical bug in JS logic — a typo in an API endpoint, incorrect calculation in cart — you need to deliver the fix immediately without waiting for review. CodePush (Microsoft AppCenter) solves this: JS bundle and resources update over the air, native code stays the same.
How CodePush Works
A React Native app consists of a native host (Objective-C/Swift / Java/Kotlin) and a JS bundle. CodePush replaces the JS bundle and resources (images/, fonts/) without updating the native part. Apple and Google allow this — as long as the update doesn't fundamentally change app behavior (you can't add new native permissions or change the business model through JS).
Integration
Installation:
npm install react-native-code-push
npx pod-install # iOS
In AppDelegate.mm (iOS):
#import <CodePush/CodePush.h>
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [CodePush bundleURL];
#endif
}
In the main component:
import CodePush from 'react-native-code-push';
const App = () => {
// ... component
};
const codePushOptions = {
checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
installMode: CodePush.InstallMode.ON_NEXT_RESUME,
mandatoryInstallMode: CodePush.InstallMode.IMMEDIATE,
};
export default CodePush(codePushOptions)(App);
InstallMode.ON_NEXT_RESUME — update applies on next return from background. Doesn't interrupt the user. IMMEDIATE — only for critical mandatory updates.
Deployment via Fastlane
lane :codepush_staging do
sh("appcenter codepush release-react \
-a MyOrg/MyApp-iOS \
-d Staging \
--description '#{ENV["CHANGELOG"]}' \
--target-binary-version '~1.2'")
sh("appcenter codepush release-react \
-a MyOrg/MyApp-Android \
-d Staging \
--description '#{ENV["CHANGELOG"]}' \
--target-binary-version '~1.2'")
end
--target-binary-version '~1.2' — semver expression. Only users with native version 1.2.x get the update. This is important: if the new JS bundle uses a native module added in 1.3, you can't push it to 1.2 users.
Rollout Strategy
Don't roll out CodePush to 100% of users immediately. AppCenter supports --rollout:
appcenter codepush release-react \
-a MyOrg/MyApp-iOS \
-d Production \
--rollout 10
10% of users get the update. After 30 minutes, check Firebase Crashlytics — if crash rate didn't increase, expand via AppCenter UI to 50% → 100%.
Limitations and What Doesn't Work
CodePush cannot update:
- Native code (Swift/ObjC/Kotlin/Java)
- Native dependencies (adding a new
podoraar) -
AndroidManifest.xmlandInfo.plist - Splash screen and app icon
If a PR touches the native part — use standard release through the Store.
CodePush from Microsoft AppCenter is deprecated in favor of EAS Update (Expo). For non-Expo projects — consider migrating to a self-hosted CodePush server (code-push-server open source) for independence from AppCenter.
Monitoring Updates
AppCenter Deployments shows statistics: how many devices got the update, how many rolled back. Automatic rollback kicks in if the app crashes right after updating — CodePush returns the previous bundle.
Process
SDK integration → AppCenter app setup → Deployment environment configuration (Staging, Production) → Fastlane lanes → add to CI → test rollout on Staging → deploy process documentation.
Timeline: 2–3 days. Cost is calculated individually.







