Guide

The Complete Guide to React Native OTA Updates

Everything you need to know about React Native OTA updates. From basics to advanced deployment strategies, this is the definitive guide for mobile developers.

S
SwiftPatch Team
Engineering
20 min read

Introduction

Over-the-Air (OTA) updates have fundamentally changed how React Native teams ship software. Instead of waiting days for App Store review every time you need to push a bug fix, you can deliver updates to your users in seconds.

This is the complete guide to React Native OTA updates. Whether you're a solo developer or part of a large engineering team, by the end of this guide you'll understand everything from the fundamentals to advanced deployment strategies.

What Are OTA Updates?

OTA (Over-the-Air) updates allow you to update your React Native app's JavaScript code and assets without going through the App Store or Google Play review process. When a user opens your app, the OTA SDK silently checks for updates, downloads any available patches, and applies them — all without requiring the user to visit the app store.

Why OTA Updates Matter

Traditional mobile app deployment:

1. Developer fixes bug
2. Submit to App Store / Google Play
3. Wait 1-7 days for review
4. Users must manually update
5. Weeks until majority adoption
Total time: 1-3 weeks

With OTA updates:

1. Developer fixes bug
2. Push OTA update via CLI
3. Update available in < 60 seconds
4. Users get update automatically on next launch
5. 90%+ adoption within 48 hours
Total time: Minutes

The Business Case

  • Mean Time to Recovery (MTTR): Reduced from days to minutes
  • User satisfaction: Critical bugs fixed before most users notice
  • App store ratings: Fewer 1-star reviews from unfixed bugs
  • Developer velocity: Ship multiple updates per day without friction
  • Conversion rates: A/B test flows and optimize in real-time

How OTA Updates Work in React Native

React Native apps have a unique architecture that makes OTA updates possible:

The Two-Layer Architecture

┌─────────────────────────────────────┐
│         JavaScript Layer            │
│  (React components, business logic, │
│   styles, navigation, assets)       │
│                                     │
│  ✅ OTA Updatable                   │
├─────────────────────────────────────┤
│           Native Layer              │
│  (Objective-C, Swift, Java, Kotlin, │
│   native modules, permissions)      │
│                                     │
│  ❌ Requires App Store Submission   │
└─────────────────────────────────────┘

The JavaScript layer runs inside an interpreter (Hermes or JavaScriptCore). Because it's interpreted code, you can replace the JavaScript bundle at any time without modifying the compiled native binary.

The Update Lifecycle

1. BUILD: Developer runs build → JavaScript bundle generated
2. UPLOAD: Bundle uploaded to OTA server
3. DIFF: Server computes differential patch
4. CHECK: App launches → SDK queries for updates
5. DOWNLOAD: SDK downloads patch in background
6. APPLY: On next restart, new bundle is loaded
7. VERIFY: SDK verifies bundle integrity
8. MONITOR: SDK monitors app health post-update

Architecture Overview

Client SDK

  • Checking for available updates
  • Downloading updates in the background
  • Applying updates on app restart
  • Verifying bundle integrity and signatures
  • Monitoring health after updates
  • Triggering automatic rollback if needed

Server

  • Storing bundle versions and patches
  • Computing differential patches
  • Serving the right patch to each device
  • Tracking rollout percentages
  • Managing environments and channels
  • Providing analytics and metrics

CDN

  • Sub-100ms response times globally
  • Automatic geographic routing
  • Edge caching for popular updates
  • High availability (99.99% uptime)
Architecture Overview:

Developer → CLI → SwiftPatch Server → CDN → Mobile App
                        ↓
                    PostgreSQL
                   (metadata)
                        ↓
                    S3/Object Storage
                   (bundle files)

Benefits of OTA Updates

1. Instant Bug Fixes

No more waiting for App Store review. Fix critical production bugs in minutes.

2. Faster Iteration

Ship multiple updates per day. Test ideas quickly and iterate based on real user feedback.

3. Higher Update Adoption

App store updates require manual user action. OTA updates are automatic — adoption rates are 90%+ within 48 hours compared to 30-50% for store updates.

4. A/B Testing

Test different UI variations, flows, or features with subsets of your users before rolling out to everyone.

5. Reduced Risk

Staged rollouts and automatic rollback mean you can deploy with confidence, knowing you have a safety net.

6. Lower Operational Costs

Fewer emergency app store submissions, faster incident resolution, and reduced support tickets.

Limitations: What You Can't Update

Understanding OTA limitations is crucial for planning your development workflow.

Cannot Update via OTA

  • Native modules: Any Objective-C, Swift, Java, or Kotlin code
  • Native dependencies: npm packages that include native code (e.g., react-native-camera with new native features)
  • App permissions: Adding new permissions (camera, location, etc.)
  • Build configuration: Changes to Info.plist, AndroidManifest.xml
  • App metadata: App icon, launch screen, app name
  • Native navigation: Changes to native navigation controllers
  • OS-level features: Widgets, extensions, watch apps

How to Handle Native Changes

  1. Push the native changes through the App Store / Google Play
  2. Use OTA updates for any JavaScript changes that accompany the native update
  3. Target OTA updates to specific binary versions
# Target OTA updates to users on binary version 2.0 or higher
swiftpatch release --platform all --target-binary ">=2.0.0"

Getting Started with SwiftPatch

Prerequisites

  • React Native 0.60 or higher
  • Node.js 16 or higher
  • npm or yarn

Step 1: Create a SwiftPatch Account

Visit swiftpatch.io and create a free account. The free tier includes 5,000 deploys per month.

Step 2: Install the CLI

npm install -g swiftpatch-cli
swiftpatch login

Step 3: Install the SDK

npm install swiftpatch

Step 4: Initialize SwiftPatch

// App.tsx
import { SwiftPatch } from 'swiftpatch';

SwiftPatch.init({
  deploymentKey: 'YOUR_DEPLOYMENT_KEY',
  autoRollback: true,
  checkFrequency: 'ON_APP_RESUME',
});

export default function App() {
  return (
    // Your app components
  );
}

Step 5: iOS Configuration

cd ios && pod install && cd ..

SwiftPatch automatically configures CocoaPods. No manual changes to AppDelegate needed.

Step 6: Android Configuration

SwiftPatch auto-links on React Native 0.60+. No manual configuration needed.

Step 7: Create Your App

swiftpatch app create --name "My App" --platform all

Step 8: Deploy Your First Update

# Make a code change, then:
swiftpatch release --platform all --description "My first OTA update!"

Step 9: Verify

Open your app, close it, and reopen it. The update will be applied on the second launch.

# Check deployment status
swiftpatch status

Configuration Options Explained

Update Strategy

SwiftPatch.init({
  // IMMEDIATE: Download and apply right away (may restart app)
  // ON_NEXT_RESTART: Download now, apply on next cold start
  // ON_NEXT_RESUME: Download now, apply when app comes to foreground
  updateStrategy: 'ON_NEXT_RESTART',
});

Check Frequency

SwiftPatch.init({
  // ON_APP_START: Check once when app starts
  // ON_APP_RESUME: Check when app comes to foreground
  // MANUAL: Only check when you call SwiftPatch.checkForUpdate()
  checkFrequency: 'ON_APP_RESUME',
});

Mandatory Updates

# Mark an update as mandatory (forces immediate install)
swiftpatch release --platform all --mandatory --description "Critical security fix"
SwiftPatch.init({
  onUpdateAvailable: (update) => {
    if (update.isMandatory) {
      // Force update
      SwiftPatch.applyUpdate();
    }
  },
});

Deployment Strategies

1. Immediate Deployment

Best for critical bug fixes:

swiftpatch release --platform all --rollout 100 --mandatory

2. Staged Rollout

Best for feature updates and non-critical changes:

swiftpatch release --platform all --rollout 1
# Monitor...
swiftpatch promote --rollout 10
# Monitor...
swiftpatch promote --rollout 50
# Monitor...
swiftpatch promote --rollout 100

3. Scheduled Deployment

Best for planned releases:

swiftpatch release --platform all --schedule "2026-02-15T10:00:00Z"

4. Environment-Based

Best for teams with QA processes:

swiftpatch release --environment staging
# QA testing...
swiftpatch promote --from staging --to production --rollout 1

Rollback Strategies

Automatic Rollback

SwiftPatch.init({
  autoRollback: true,
  healthCheckTimeout: 30000,
  onRollback: (info) => {
    console.log('Rolled back from', info.rolledBackVersion);
  },
});

Manual Rollback

# Rollback to previous version
swiftpatch rollback

# Rollback to specific version
swiftpatch rollback --version 1.2.3

Preventive Rollback

If monitoring reveals issues before automatic detection:

# Halt rollout immediately
swiftpatch rollback --deployment dep_abc123

Security

Bundle Signing

# Generate keys
swiftpatch generate-keys --algorithm ed25519

# Sign releases
swiftpatch release --platform all --sign --private-key ./private.key
SwiftPatch.init({
  publicKey: 'YOUR_PUBLIC_KEY',
  requireSignature: true,
});

HTTPS Enforcement

All SwiftPatch communications use HTTPS by default. Certificate pinning is available for additional security.

Integrity Verification

Every bundle is verified against a SHA-256 hash before being applied. If the hash doesn't match, the update is rejected.

CI/CD Integration

GitHub Actions

name: Deploy OTA
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test
      - run: npm run build
      - run: npx swiftpatch release --platform all --rollout 1
        env:
          SWIFTPATCH_ACCESS_KEY: ${{ secrets.SWIFTPATCH_ACCESS_KEY }}

Other CI/CD Platforms

  • CircleCI
  • GitLab CI
  • Bitbucket Pipelines
  • Jenkins
  • Azure DevOps
  • AWS CodePipeline

Monitoring and Analytics

Dashboard Metrics

  • Active deployments and their status
  • Update adoption rates over time
  • Rollback events and reasons
  • Error rates per version
  • Download success/failure rates
  • Bundle sizes and patch sizes

CLI Monitoring

# View deployment status
swiftpatch status

# List recent deployments
swiftpatch deployments --limit 10

# View specific deployment details
swiftpatch deployment-info --id dep_abc123

Webhook Integration

# Set up webhooks for deployment events
swiftpatch webhooks add --url https://your-server.com/webhook --events deploy,rollback

Troubleshooting Common Issues

Update Not Being Applied

Symptoms: You deploy an update but users don't see changes.

  1. App hasn't been restarted after download
  2. Deployment key mismatch
  3. Binary version targeting excludes current users
  4. Rollout percentage hasn't reached the user
# Verify deployment status
swiftpatch status --verbose

Slow Update Downloads

Symptoms: Updates take too long to download.

  1. Verify differential patching is working (check patch size)
  2. Check CDN health status
  3. Ensure the user has reasonable network connectivity

Crash After Update

Symptoms: App crashes after applying an OTA update.

  1. Automatic rollback should handle this if enabled
  2. Check the SwiftPatch dashboard for error details
  3. Manually rollback if auto-rollback is disabled
swiftpatch rollback

Build Errors After SDK Installation

Symptoms: iOS or Android build fails after installing SwiftPatch.

Solutions:

# iOS: Clean and reinstall pods
cd ios && pod deintegrate && pod install && cd ..

# Android: Clean build
cd android && ./gradlew clean && cd ..

# Both: Clear Metro cache
npx react-native start --reset-cache

Advanced Topics

Custom Update Logic

For apps with specific update requirements:

SwiftPatch.init({
  checkFrequency: 'MANUAL',
});

// Check for updates at a specific point in your app
async function checkUpdates() {
  const update = await SwiftPatch.checkForUpdate();

  if (update) {
    if (update.isMandatory) {
      await SwiftPatch.downloadAndApply();
    } else {
      // Download in background, apply on next restart
      await SwiftPatch.downloadUpdate();
    }
  }
}

Background Updates

Download updates in the background while the user uses the app:

SwiftPatch.init({
  updateStrategy: 'ON_NEXT_RESTART',
  downloadInBackground: true,
  onDownloadProgress: (progress) => {
    // Optionally show progress to user
    console.log(progress.percentage + '% downloaded');
  },
});

Multi-App Management

If you manage multiple React Native apps:

# List all apps
swiftpatch apps list

# Deploy to specific app
swiftpatch release --app "my-app-ios" --platform ios
swiftpatch release --app "my-app-android" --platform android

Feature Flags with OTA

Combine OTA updates with feature flags for maximum flexibility:

// Feature flag configuration (OTA updatable)
const flags = {
  newCheckoutFlow: false,
  darkModeV2: true,
  socialLoginEnabled: false,
};

// Toggle features via OTA update without code changes
export function isFeatureEnabled(flag: keyof typeof flags): boolean {
  return flags[flag] ?? false;
}

FAQ

Q: Is OTA updating free?

A: SwiftPatch offers a free tier with 5,000 deploys per month. Paid plans start at $19/month for 25,000 deploys.

Q: Does OTA work with Expo?

A: Yes. SwiftPatch works with both bare React Native and Expo projects.

Q: How fast are updates delivered?

A: Updates are typically available within 60 seconds of deployment. Users receive them on their next app launch or resume.

Q: What happens if a user is offline?

A: The SDK will check for updates the next time the device has connectivity. No updates are lost.

Q: Can I target specific users or devices?

A: Yes. You can target by binary version, platform, and rollout percentage. Custom targeting (by user segment) is available on enterprise plans.

Q: How does OTA affect app size?

A: The SwiftPatch SDK adds approximately 200KB to your app binary. Patches are downloaded at runtime and replace the existing bundle.

Q: Is OTA compliant with App Store guidelines?

A: Yes. JavaScript OTA updates are explicitly allowed by both Apple (Section 3.3.2) and Google (Developer Program Policies).

Q: Can I use OTA with React Native New Architecture?

A: Yes. SwiftPatch fully supports React Native New Architecture (Fabric and TurboModules) as of version 2.0.

Conclusion

OTA updates are no longer optional for serious React Native teams. They're the difference between waiting days to fix a critical bug and fixing it in minutes. With SwiftPatch, you get the most advanced OTA platform available — differential patching, automatic rollback, staged rollouts, and enterprise security — all with a free tier to get started.

Your users deserve faster updates. Start shipping with confidence.

Get started with SwiftPatch for free →

Ready to ship updates faster?

Get started with SwiftPatch for free. No credit card required.

Join Waitlist

Related Articles