惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

www.infosecurity-magazine.com
www.infosecurity-magazine.com
D
DataBreaches.Net
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
F
Full Disclosure
V2EX - 技术
V2EX - 技术
N
News and Events Feed by Topic
Help Net Security
Help Net Security
L
LangChain Blog
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
Google Online Security Blog
Google Online Security Blog
P
Proofpoint News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
B
Blog RSS Feed
N
Netflix TechBlog - Medium
N
News | PayPal Newsroom
TaoSecurity Blog
TaoSecurity Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
V
Vulnerabilities – Threatpost
B
Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园_首页
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
AI
AI
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cyberwarzone
Cyberwarzone
P
Proofpoint News Feed
Google DeepMind News
Google DeepMind News
G
GRAHAM CLULEY
Vercel News
Vercel News
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
博客园 - 司徒正美
C
CERT Recently Published Vulnerability Notes
GbyAI
GbyAI
Scott Helme
Scott Helme
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
A
About on SuperTechFans
P
Privacy International News Feed

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Shipping React Native Updates Without the App Store: A Practical Guide to OTA and React Native Stallion
Amanda Gama · 2026-05-12 · via DEV Community

You know the feeling. There's a typo in production copy. A misconfigured feature flag. A small logic bug that snuck past QA somehow. None of it touches native code. It's pure JavaScript, the kind of fix you could push in five minutes if the universe were fair. But the universe isn't fair, and so you wait. You wait for Apple. You wait for the Play Store staged rollout. Hours go by. Sometimes days. All for a one-line change.

This is the gap OTA updates were built to fill. In this article I want to walk through what OTA actually means in React Native land, why everything changed in 2024, and how to get up and running with React Native Stallion, which is probably the most interesting CodePush replacement to come out of that whole mess.

What OTA Updates Actually Are (and Aren't)

A React Native app is really two things in a trench coat. There's the native shell, which is your APK or IPA with all its Java, Kotlin, Objective-C and Swift. And then there's the JavaScript bundle, which is just a file that the shell loads when the app starts. The app stores care about the shell. The bundle is, from their perspective, content.

OTA exploits that gap. Instead of resubmitting the whole app, you swap the JavaScript bundle on the device. Next launch (or whenever you decide), your users are running new code.

What you can ship over the air:

  • UI changes, copy fixes, styling tweaks
  • New features written entirely in JavaScript
  • Business logic updates, API integration changes
  • Bug fixes that don't touch native modules

What you can't:

  • Updates to native modules. Added a new library with native code? Time to rebuild.
  • Permission changes. Camera, location, notifications, all of that.
  • App icons, splash screens, native configuration
  • Anything below the JavaScript layer

Both Apple and Google allow JavaScript-only OTA. They've been pretty consistent about it. What they don't allow is using OTA to fundamentally change what your app does after the fact. Hot-fixing bugs is fine. Quietly turning your meditation app into a casino is not.

Why the Whole Landscape Shifted

For years the answer to "how do we do OTA on React Native" was basically: CodePush, paired with App Center, both from Microsoft. It was free, it was well-documented, it worked. Most teams just used it and got on with their lives.

Then in 2024 Microsoft announced they were retiring App Center, with the full shutdown landing in 2025. CodePush as a hosted service went with it.

That left a lot of teams suddenly squinting at their production apps wondering what now. The replacements that emerged:

Expo EAS Update is polished and well-maintained, but tightly coupled to the Expo ecosystem. If you're already there, great. If you're on bare React Native, there's friction.

Self-hosted CodePush is technically possible since the server code is open source. The catch is you're now running infrastructure, scaling it, securing it, and on call for it.

React Native Stallion is newer, fully managed, and was built specifically to fill the CodePush void. It also makes some interesting technical bets (differential patches, bundle signing) that the older tools don't.

The rest of this article focuses on Stallion, because it's what I keep seeing teams reach for when they're migrating off CodePush and don't want to fully commit to the Expo workflow.

What Stallion Actually Gives You

A few things stand out.

Patch updates. Traditional OTA ships the entire JavaScript bundle every time. Your bundle is 20 MB, you fix a one-line bug, every user on the planet downloads 20 MB. Stallion computes a file-level diff and ships only the changed bytes. Their docs claim up to 98% size reduction depending on the change, and from what I've seen that's roughly right. On slow connections this is the difference between an update finishing in seconds and an update never finishing at all.

Bucket-based testing and promotion. Bundles get uploaded to buckets and promoted to production from the dashboard. You can also push a build to internal testers without going through TestFlight or the Play Console, which is honestly the part QA teams get most excited about.

Automatic and manual rollback. Misbehaving release? You can pause it (stops new downloads) or roll it back (reverts existing devices on next launch). Crash-on-startup automatic rollback is also baked in, which I'll get to.

Bundle signing. Every bundle is cryptographically signed, with optional customer-managed keys. This matters more than people realize. An unsigned OTA pipeline is basically a supply chain attack waiting to happen.

Open source SDK and CLI. MIT licensed. The console is hosted.

Setting It Up

Stallion has three pieces. The CLI uploads bundles. The SDK on the device downloads and applies them. The console is where you manage releases. You'll need React Native 0.69 or higher.

1. Install the SDK and CLI

# in your React Native project
npm i react-native-stallion

# globally or in your CI tooling
npm i -g stallion-cli

Enter fullscreen mode Exit fullscreen mode

Then npx pod-install to link iOS.

2. Wire Up the Native Side

You're telling React Native to load its JavaScript bundle from Stallion's storage instead of the default location. On Android that means overriding getJSBundleFile. On iOS, bundleURL.

Android (React Native 0.76+, Kotlin):

import com.stallion.Stallion

override val reactNativeHost: ReactNativeHost =
  object : DefaultReactNativeHost(this) {
    override fun getJSBundleFile(): String? {
      return Stallion.getJSBundleFile(applicationContext)
    }
  }

Enter fullscreen mode Exit fullscreen mode

iOS (React Native 0.76+, Swift):

import react_native_stallion

override func bundleURL() -> URL? {
  #if DEBUG
    return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
  #else
    return StallionModule.getBundleURL()
  #endif
}

Enter fullscreen mode Exit fullscreen mode

The #if DEBUG matters. In development you want Metro serving fresh bundles, not Stallion. OTA only kicks in for release builds.

3. Add Your Project ID and App Token

Generate both from the Stallion console under Project Settings > Access Tokens, then drop them into your native config.

iOS, in Info.plist:

<key>StallionProjectId</key>
<string>your_project_id</string>
<key>StallionAppToken</key>
<string>spb_your_app_token_here</string>

Enter fullscreen mode Exit fullscreen mode

Android, in res/values/strings.xml:

<string name="StallionProjectId">your_project_id</string>
<string name="StallionAppToken">spb_your_app_token_here</string>

Enter fullscreen mode Exit fullscreen mode

4. Wrap Your Root Component

import { withStallion } from 'react-native-stallion';

const App = () => {
  // your app
};

export default withStallion(App);

Enter fullscreen mode Exit fullscreen mode

That's the whole setup. A new release build of your app will now check Stallion for updates on launch and when it returns to the foreground.

Publishing and Promoting an Update

The actual workflow is pretty boring once you've done it once, which is what you want.

  1. Make your code change.
  2. Build the JavaScript bundle and upload it to Stallion via the CLI.
  3. In the console, pick the bundle and click "Promote Bundle." You specify the target app version, write release notes, and optionally set a rollout percentage.
  4. Next time a user's app comes to the foreground, it checks for updates and pulls the new bundle in the background.

The rollout percentage is the part worth lingering on. By default new releases start at 0%, meaning only users explicitly logged into the SDK (typically your team) get the update. You then dial it up. 5%, 25%, 50%, 100%, watching adoption and crash metrics as you go. It's the same phased rollout pattern you'd use on the Play Store, except you're holding the dial directly instead of submitting paperwork to Google.

Custom Update UX

By default Stallion downloads silently in the background and the new bundle takes effect on the next cold start. For most apps that's the right behavior. Sometimes though you want to prompt the user, especially for important fixes. "Hey, there's an update ready, want to restart now?"

The SDK exposes a hook for exactly this:

import { useStallionUpdate, restart } from 'react-native-stallion';

const UpdateBanner = () => {
  const { isRestartRequired } = useStallionUpdate();

  if (!isRestartRequired) return null;

  return (
    <View style={styles.banner}>
      <Text>A new update is ready.</Text>
      <Button title="Restart" onPress={restart} />
    </View>
  );
};

Enter fullscreen mode Exit fullscreen mode

useStallionUpdate also gives you metadata about the new bundle, including release notes and version info, so you can surface something meaningful rather than a generic "update available" toast.

When Things Go Wrong

This is the part most teams underestimate when they're picking an OTA platform. You will, eventually, ship a broken bundle to production. The question is how fast you can recover.

Stallion gives you two levers from the dashboard.

Pause stops the release from downloading to any new device. Devices that already have it stay on it. Useful when you've spotted a problem but it's not severe enough to roll back.

Rollback pauses the release and tells devices that already pulled it to revert to the previous stable bundle on next launch. This is the nuclear option, and it's the one you want when something is really wrong.

There's also automatic rollback for the worst case: if a new bundle causes the app to crash before it can mark itself as healthy, the SDK reverts on next launch. This is the safety net that lets you sleep through a 3 AM bad deploy. (Not that you should, but you can.)

Some Honest Tradeoffs

OTA is a force multiplier, but it's not free. A few things worth chewing on before you commit.

You're adding a runtime dependency on a vendor. Stallion is well-maintained and the SDK is open source, but your update pipeline now depends on their availability. Worth understanding their SLA story before you wire critical workflows around it.

Native code changes still go through the app store. OTA doesn't reduce that cadence. It just lets you patch JavaScript faster between native releases.

Testing discipline matters more, not less. Faster shipping is also faster shipping of bugs. The teams that get the most out of OTA are the ones with solid CI, automated tests, and the discipline to actually use phased rollouts. Without that you've just built a faster way to break production.

App Store review policies still apply. Don't use OTA to dodge review. Apple has been clear that meaningful changes to app functionality need to go through the normal process.

Wrapping Up

If you're running React Native in production in 2026, OTA isn't really optional anymore. Your competitors have it. Your users expect bug fixes in days, not weeks. The "wait for the next release cycle" argument basically never wins against "patch it tonight."

CodePush is gone. The choices are Expo, build your own, or pick up something like Stallion. For teams on bare React Native who want CodePush-style ergonomics with some modern conveniences (patch updates, signed bundles, dashboard rollouts), Stallion is a reasonable default to evaluate.

Setup is an afternoon. Using it well takes longer, but that's true of any deployment pipeline. Start with internal beta. Ramp through phased rollouts. Watch your crash metrics. Keep the rollback button close.