Implementing CodePush in React Native

Master over-the-air updates to deploy JavaScript changes directly to user devices--bypassing app store reviews for faster iteration cycles.

What is CodePush and Why It Matters

CodePush is a cloud service provided by Microsoft (as part of App Center) that enables React Native developers to deploy updates directly to users' devices. When you push JavaScript code changes, CodePush delivers them the next time the app connects to the server, bypassing the App Store and Google Play Store review processes entirely.

The primary benefit is rapid iteration. Critical bug fixes can reach users within hours instead of days or weeks. Small UI tweaks, configuration changes, and A/B testing scenarios become straightforward to implement without the overhead of store submissions. This capability proves especially valuable for applications serving large user bases where the friction of traditional updates results in significant version fragmentation.

CodePush specifically targets the JavaScript bundle and any assets you include in your deployment. Native code changes--modifications to Swift, Objective-C, Java, or Kotlin files--still require standard app store submissions. This distinction is crucial for planning your update strategy.

The Primary Benefits

  • Rapid Iteration: Critical bug fixes reach users within hours instead of days or weeks
  • Reduced Friction: No app store downloads or review cycles for JavaScript updates
  • Version Control: Maintain multiple deployment environments (Staging/Production)
  • Rollback Capability: Instantly revert problematic updates

The service maintains multiple deployment environments, allowing you to test updates before broad release. Each deployment tracks its own update history, enabling rollback capabilities and graduated rollouts.

How CodePush Works

The CodePush plugin integrates with your React Native app's lifecycle, checking for updates when the app launches or returns from the background. When an update is available, it downloads in the background and applies on the next app restart. This approach ensures users always have a working version while receiving updates asynchronously.

Update Workflow

  1. Check: App connects to CodePush server and checks for available updates
  2. Download: If an update exists, it downloads in the background
  3. Apply: Update installs on next app restart (or immediately for mandatory updates)

The service maintains multiple deployment environments (typically Staging and Production), allowing you to test updates before broad release. Each deployment tracks its own update history, enabling rollback capabilities and graduated rollouts. As noted by React Native core contributors at Callstack, this OTA workflow is essential for emergency deployments where traditional app store review processes would introduce unacceptable delays.

The service specifically targets the JavaScript bundle and any assets you include in your deployment. Native code changes--modifications to Swift, Objective-C, Java, or Kotlin files--still require standard app store submissions.

Setting Up CodePush in Your React Native Project

Prerequisites and Installation

Before installing CodePush, ensure you have a React Native project set up with version compatibility that matches the CodePush plugin version you plan to use. The installation process involves adding the npm package and linking native dependencies.

Begin by installing the CodePush CLI tool globally, which you'll use to deploy updates:

npm install -g appcenter-cli

Then install the CodePush plugin within your React Native project:

npm install --save react-native-code-push

For React Native 0.60 and above, autolinking handles the native module integration. For older versions, you'll need to manually link the module:

react-native link react-native-code-push

Configuring the App Center Connection

CodePush requires App Center for management, so you'll need to create an App Center account and register your application. The CLI uses your App Center credentials to authenticate and manage deployments:

appcenter login

This opens a browser window for authentication. After logging in, you can create your app in App Center and obtain the deployment key that CodePush uses to identify your application.

Create your app in App Center using the CLI:

appcenter apps create -d "YourAppName" -p "React-Native" -o "iOS" --ios-public-app-type
appcenter apps create -d "YourAppName" -p "React-Native" -o "Android" --android-public-app-type

For each platform, retrieve the deployment key:

appcenter codepush deployment list -a "YourOwner/YourAppName-iOS" -k

You'll typically work with two deployments: Staging for testing and Production for end users. As documented in the official CodePush documentation, this separation is essential for maintaining a safe testing environment before production releases.

Integrating CodePush in Your Application Code

With the package installed and keys obtained, integrate CodePush into your application entry point. The most common approach wraps your root component with the CodePush higher-order component, configuring sync behavior to match your requirements:

import codePush from 'react-native-code-push';

const codePushOptions = {
 checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
 installMode: codePush.InstallMode.ON_NEXT_RESTART,
 mandatoryInstallMode: codePush.InstallMode.IMMEDIATE,
 rollbackRetryOptions: {
 maxRetryAttempts: 3,
 delayInSecondsBetweenRetryAttempts: 60
 }
};

const App = () => {
 // Your app component
};

export default codePush(codePushOptions)(App);

This configuration checks for updates when the app resumes from the background, installs mandatory updates immediately, and attempts automatic rollback if the update fails during the retry window. The CheckFrequency enum offers several options including ON_APP_START for immediate checks and MANUAL for developer-triggered updates.

The official CodePush documentation provides comprehensive coverage of all available API methods and configuration options for fine-tuning update behavior to match your specific deployment requirements.

For styling your React Native components alongside CodePush integration, consider exploring Emotion in React for consistent styling approaches that work well with dynamic updates.

CodePush API Methods and Configuration Options

Understanding the Sync Options

The sync method provides a convenient wrapper that handles the entire update workflow--checking for updates, downloading them, and installing appropriately. Understanding its configuration options allows you to tailor behavior to your use case:

codePush.sync(
 {
 updateDialog: {
 appendReleaseDescription: true,
 descriptionPrefix: '\n\nChange log: ',
 mandatoryUpdateMessage: 'A new version is required.',
 mandatoryContinueButtonLabel: 'Update',
 optionalUpdateMessage: 'An update is available.',
 optionalIgnoreButtonLabel: 'Ignore',
 optionalInstallButtonLabel: 'Install'
 },
 installMode: codePush.InstallMode.ON_NEXT_RESUME,
 mandatoryInstallMode: codePush.InstallMode.IMMEDIATE,
 deploymentKey: 'YOUR_DEPLOYMENT_KEY',
 rollbackTimeout: 30000,
 ignoreFailedUpdates: false
 },
 (status) => {
 switch (status) {
 case codePush.SyncStatus.UP_TO_DATE:
 console.log('App is up to date');
 break;
 case codePush.SyncStatus.UPDATE_INSTALLED:
 console.log('Update installed, will apply on restart');
 break;
 case codePush.SyncStatus.SYNC_IN_PROGRESS:
 console.log('Sync in progress');
 break;
 }
 },
 (downloadProgress) => {
 console.log(`Download progress: ${downloadProgress.receivedBytes}/${downloadProgress.totalBytes}`);
 }
);

The updateDialog configuration controls how optional updates are presented to users. Mandatory updates bypass user consent entirely and install according to the mandatoryInstallMode setting--IMMEDIATE for immediate installation or ON_NEXT_RESUME for installation when the app returns to the foreground. Optional updates display the dialog and respect user preferences.

Manual Update Control

For scenarios requiring more granular control, the CodePush API provides individual methods for checking, downloading, and installing updates. This approach works well when you want to implement custom update flows or integrate updates into existing settings screens:

// Check for updates manually
const checkForUpdate = async () => {
 try {
 const update = await codePush.checkForUpdate();
 if (update) {
 setHasUpdate(true);
 setUpdateMetadata(update);
 }
 } catch (error) {
 console.error('Error checking for updates:', error);
 }
};

// Download and install an update
const downloadAndInstall = async () => {
 try {
 await codePush.sync({
 installMode: codePush.InstallMode.IMMEDIATE,
 deploymentKey: 'YOUR_DEPLOYMENT_KEY'
 });
 } catch (error) {
 console.error('Error downloading update:', error);
 }
};

// Get current update metadata
const getCurrentPackage = async () => {
 const pkg = await codePush.getCurrentPackage();
 console.log('Current package:', pkg);
};

Working with Deployment Keys

Different deployment environments require different keys. For iOS and Android, you maintain separate keys in App Center. Within each platform, Staging and Production keys serve different purposes:

const getDeploymentKey = () => {
 if (__DEV__) {
 return 'STAGING_DEPLOYMENT_KEY';
 }
 return Platform.select({
 ios: 'IOS_PRODUCTION_KEY',
 android: 'ANDROID_PRODUCTION_KEY'
 });
};

codePush.sync({
 deploymentKey: getDeploymentKey()
});

Environment-based key selection ensures your development builds receive staging updates while production builds receive production updates. This separation prevents accidental testing deployments to real users.

Key CodePush Configuration Options

Tailor update behavior to match your deployment strategy

Check Frequency

ON_APP_START, ON_APP_RESUME, or MANUAL for developer-triggered checks

Install Modes

ON_NEXT_RESTART, IMMEDIATE, or ON_NEXT_RESUME depending on update urgency

Mandatory Updates

Critical fixes install immediately without user consent

Rollback Retry

Automatic retry attempts when update installation fails

Deployment Keys

Separate keys for Staging and Production environments

User Dialog

Customizable update prompts for optional updates

Deployment Strategies for Production Use

Implementing Gradual Rollouts

CodePush supports phased releases that gradually expose updates to your user base. This approach catches issues before they affect all users, as recommended by React Native experts at Callstack:

# Deploy to 10% of users initially
appcenter codepush release-react \
 -a "YourOwner/YourAppName-iOS" \
 --mandatory \
 --rollout 10

The --rollout parameter specifies the percentage of devices that will receive the update. Monitor crash reports and user feedback, then increase the rollout as confidence grows:

# Increase rollout to 50%
appcenter codepush modify -a "YourOwner/YourAppName-iOS" \
 -d Production \
 --rollout 50

Phased rollouts combine effectively with the mandatory flag. Critical bug fixes might deploy as mandatory to all users immediately, while feature updates roll out gradually as optional.

Rollback Procedures and Error Handling

When updates cause issues, CodePush provides mechanisms to recover. The automatic rollback feature attempts to revert to the previous version when the updated app crashes repeatedly during the rollback window:

const codePushOptions = {
 rollbackRetryOptions: {
 maxRetryAttempts: 3,
 delayInSecondsBetweenRetryAttempts: 60
 }
};

For manual intervention, you can promote a previous version or explicitly rollback through the CLI:

# List all deployments to identify the working version
appcenter codepush deployment list -a "YourOwner/YourAppName-iOS" -k

# Rollback to a specific label
appcenter codepush rollback -a "YourOwner/YourAppName-iOS" Production --targetRelease v1

The rollback command marks the specified version as broken, automatically reverting all devices to their previous installation. This works because CodePush maintains the previous bundle alongside updates, allowing instant rollback without re-downloading.

Version Management and Update Targeting

Effective update targeting prevents version compatibility issues. CodePush labels each release with a version identifier, and you can target specific app versions:

# Release update only to users on app version 1.0.0
appcenter codepush release-react \
 -a "YourOwner/YourAppName-iOS" \
 --targetBinaryVersion "1.0.0"

# Release to a range of versions
appcenter codepush release-react \
 -a "YourOwner/YourAppName-iOS" \
 --targetBinaryVersion "~1.0.0"

The tilde operator (~) includes minor version updates, while the caret operator (^) includes major version updates. This flexibility supports scenarios where you maintain multiple app versions in the wild.

Best Practices for Production CodePush Implementations

Performance Optimization

CodePush updates should be designed with performance in mind. Bundle size directly impacts download time and user experience:

# Optimize bundle before release
react-native bundle \
 --platform android \
 --dev false \
 --entry-file index.js \
 --bundle-output android/app/src/main/assets/index.android.bundle \
 --assets-dest android/app/src/main/res/

Smaller bundles download faster and install more reliably, especially on mobile networks. Remove unused dependencies, implement code splitting for large applications, and consider asset optimization as part of your build process. As noted by Callstack's engineering team, performance optimization is critical for maintaining positive user experience during updates.

Security Considerations

CodePush operates outside the app store review process, which places additional responsibility on developers to validate update integrity:

  • Use HTTPS for all CodePush communications (enforced by the SDK)
  • Validate update signatures when available
  • Implement server-side authorization for release commands
  • Monitor for unauthorized release attempts through App Center alerts

The App Center infrastructure provides security guarantees, but your deployment practices should include review processes for production releases, similar to how you would review code before merging.

Monitoring and Analytics Integration

Combine CodePush with crash reporting and analytics to validate update success:

codePush.sync({
 installMode: codePush.InstallMode.IMMEDIATE
}, (status) => {
 if (status === codePush.SyncStatus.UPDATE_INSTALLED) {
 analytics.track('codepush_update_installed');
 }
});

Track metrics including update adoption rate, crash rate changes after updates, and user engagement metrics to identify problematic deployments early. This proactive monitoring approach helps catch issues before they affect significant portions of your user base.

For comprehensive React Native project planning, including CI/CD integration with CodePush, explore our guide on using React Flow to plan React projects. Additionally, learn about Tailwind CSS with React and Vue.js for styling strategies that complement your update workflows.

Troubleshooting Common CodePush Issues

Update Installation Failures

When updates fail to install, common causes include insufficient storage space, network interruptions, and bundle format mismatches. The SDK logs detailed error information that helps diagnose issues:

codePush.sync({
 installMode: codePush.InstallMode.ON_NEXT_RESTART
}, (status) => {
 if (status === codePush.SyncStatus.ERROR) {
 console.error('Sync error occurred');
 }
}, (progress) => {
 // Monitor download progress
});

Enable debugging to see CodePush logs during development:

codePush.sync({
 deploymentKey: 'YOUR_KEY'
}, null, null, (progress) => {
 console.log(`Progress: ${progress.receivedBytes}/${progress.totalBytes}`);
});

Version Compatibility Issues

App version mismatches prevent updates from applying. Ensure your CodePush deployment targets match the app versions you're supporting:

# Check binary version compatibility
appcenter codepush deployment list -a "YourOwner/YourAppName-iOS" -k

# Release with specific version targeting
appcenter codepush release-react \
 -a "YourOwner/YourAppName-iOS" \
 --targetBinaryVersion "1.0.0 - 1.5.0"

Debug Symbols and Source Maps

For production debugging, include source maps with your releases:

appcenter codepush release-react \
 -a "YourOwner/YourAppName-iOS" \
 --sourcemap-output ./ios/main.jsbundle.map

Source maps enable you to trace errors in deployed bundles back to your original source code, significantly improving debugging efficiency for CodePush updates.

Common Pitfalls to Avoid

Based on implementation guidance from practical CodePush tutorials, avoid these common mistakes:

  1. Skipping Staging testing: Always verify updates in Staging before Production release
  2. Large bundle sizes: Optimize bundles to reduce download time and failure rates
  3. Ignoring rollback mechanisms: Configure rollback options before deploying to production
  4. Missing version targeting: Use --targetBinaryVersion to prevent compatibility issues

Conclusion

Implementing CodePush in React Native transforms your update workflow from a multi-day process involving app store reviews into a near-instantaneous delivery mechanism. The key to successful implementation lies in understanding the architecture--CodePush delivers JavaScript and asset changes while native code changes still require store submissions--and implementing appropriate strategies for your deployment environment.

Quick Start Checklist

  1. Install CodePush CLI and plugin
  2. Configure App Center and create deployments
  3. Integrate CodePush with your root component
  4. Test updates in Staging before Production release
  5. Use gradual rollouts for production updates
  6. Implement monitoring to catch issues early

Start with a Staging deployment for testing, use the sync API with appropriate configuration for your update frequency needs, implement gradual rollouts for production releases, and maintain monitoring to catch issues early. With these practices in place, CodePush becomes a powerful tool for maintaining and improving your React Native application post-deployment.

Next Steps

Ready to implement CodePush in your React Native project? Our web development team specializes in modern mobile deployment workflows. We can help you set up automated update pipelines, implement monitoring solutions, and optimize your app delivery process for faster iteration cycles. Contact us to discuss how we can accelerate your mobile app development.

Frequently Asked Questions

Ready to Modernize Your Mobile App Deployment?

Our team specializes in React Native development and DevOps automation. Let us help you implement efficient update workflows that accelerate your release cycles.

Sources

  1. Microsoft React Native CodePush README - Official CodePush documentation with setup steps, API methods, and configuration options
  2. Callstack: Ship OTA When in an Emergency - Production-ready OTA deployment strategies from React Native core contributors
  3. iFlair: Over-the-Air (OTA) Updates with CodePush in React Native - Step-by-step implementation workflow and troubleshooting guidance