Loading... Search articles

Search for articles

Sorry, but we couldn't find any matches...

But perhaps we can interest you in one of our more popular articles?
Designing scalable OTA update architecture for React Native

Designing scalable OTA update architecture for React Native

Aug 20, 2026 - 5 min read

This article is written by Zach Goldie

Self-hosting OTA updates became common after App Center and CodePush shut down in 2025. CodePush had been the popular free option, but the remaining hosted services easily hitting five or six figure bills for popular apps.

For staging-only or use with small user bases, self-hosting is fairly straight forwards. But, as the user base grows, the architecture can start to struggle and bolt on pieces are required.

This is why we redesigned the approach for Codemagic Patch to run smoothly, even with millions of end users.

The bottleneck in most OTA servers

At Codemagic we ran a hosted CodePush service that served billions of updates. That high volume meant a huge number of update checks. This is because in the usual setup:

  • Each device checks for updates regularly, often around app launch or restart.
  • Each check is a request to your server API.
  • That request involves application logic and a few database queries.
  • Only some checks lead to a download, while most answers are “you’re up to date”.

If you have thousands of users, this server load is fine. With millions of users, it looks like a call center with one phone and thousands of callers.

Typical OTA architecture: update checks hit the API and database on every poll
Typical OTA architecture: update checks hit the API and database on every poll

All of those callers require an answer from the server, even when the answer is “you’re up to date”.

The typical route to compensate

You can compensate for that load with extra infrastructure:

  • Autoscaling and load balancing for more throughput
  • Response caching with Redis so fewer checks hit the database
  • Careful cache invalidation so releases still show up correctly

Those tactics do work, and plenty of companies have setups of this type to serve large user bases. But, they add complexity and ways for the service to go wrong.

Response caching helps, but it’s not fixing the fundamental problem. You are still running a call center, just one that’s more efficient.

From call center to bulletin board

We realised we could overhaul this approach when thinking about the shape of the requests and responses.

Every device is only asking a small question with minimal variations:

I’m on this deployment and version, so what is the latest compatible bundle?

For any given deployment and binary version, the answer for “what is the latest relevant release?” is fixed until you publish again or increase a rollout. Database queries are overkill for this type of request with limited questions and answers.

A pre-generated document is a much better fit. So instead of answering every poll in the API, you can:

  1. Generate a small JSON manifest when you publish.
  2. Scope that manifest to the relevant deployment and binary version.
  3. Store it on object storage.
  4. Serve it through a CDN.

That way, instead of calling the API, the app fetches a static file from the CDN at a URL such as https://patch.example.com/{deployment_key}/{binary_version}/manifest.json to see which bundle it should run.

With this change, the model is closer to checking a bulletin board than phoning a call center. The answer is already posted, so each device just reads it. That allows update checks to comfortably scale to many millions of devices.

While other OTA update tools serve the download bundle via the CDN, shifting these regular checks is what makes Codemagic Patch a fully CDN-first architecture.

CDN-first OTA architecture: clients fetch pre-generated manifests from object storage and the CDN
CDN-first OTA architecture: clients fetch pre-generated manifests from object storage and the CDN

Load test comparison

To test the difference, we compared Patch with Hot Updater, another popular self-hosted OTA tool. We used their documented setup for Cloudflare, alongside Patch hosted on a 2GB VM, then ramped up the request rate.

As the traffic increased, Hot Updater started to struggle under the update-check load. Patch continued to handle around 1,000 requests per second in that test, because the request was serving pre-generated manifests rather than answering live API and SQL work for every check.

This isn’t to say Hot Updater can’t work for high volumes. They document an AWS setup with response caching, similar to we described earlier. But Patch has an architecture that can handle those volumes with just a basic setup.

Simulated crash test

A secondary benefit of CDN-first delivery is failure isolation.

When both the manifests and bundles live on object storage behind a CDN, the server going down doesn’t stop the checks and downloads from working.

We performed a crash-style test where we took the server offline, showing that checks and downloads continued to work from the already published artifacts.

You still need the machine running to publish releases, collect metrics and operate the dashboard. But, you don’t need it to answer every device request.

Try the local evaluation stack

Codemagic Patch is our take on that bulletin board model that doesn’t require complexity to self-host at scale.

The fastest way to play with Patch is by running the local evaluation stack as described in the quickstart doc. With Docker Compose v2 and Node.js 22+, you can bring up the real server, worker, Postgres, MinIO, and dashboard on your machine without public domains or a GitHub OAuth app:

git clone https://github.com/codemagic-ci-cd/codemagic-patch.git
cd codemagic-patch
./scripts/local-eval/up.sh

That uses docker-compose.dev.yml under the hood and seeds enough team and app data to publish a test release locally. When you are done, tear it down with:

docker compose -f docker-compose.dev.yml down -v

From there, the docs have the full guide for production self-hosting if you want to take the same architecture beyond localhost. For the full details, visit the site:

patch.codemagic.io

Related articles

Latest articles

Show more posts