NewBenchmark: how xprem handles a 1M MAU fleet on a single vCPU

Self-hosted OTA Updates server for Expo & React-native Apps

xprem is a self-hosted, open-core server (MIT) implementing the expo-updates and expo-observe protocols. It works with most major cloud providers for bucket storage and content delivery (CDN).

Get startedGitHub521
Deploy with your agent

Open a reviewable prompt in

ClaudeChatGPTCursor

Starred by seanc, Ebaneck, sleftsito, xNeuNoRo, tarhansy and 516 others

rider · zshota.xprem.dev

~/rider $ npx eoas publish --branch production

Exporting bundleios · android · hermes0.9s

Uploading assetss3://ota-updates · 412 files · 2.1 MB1.4s

Publishing to branchproduction0.2s

Update 1784952901 is live on production

devices pick it up on their next check-in

~/rider $

Complete OTA management, out of the box.

All the features of a hosted OTA service, on your server.

ota.xprem.dev/branches/production
1.24M96.6%3714
25%

Dashboard

Browse updates per branch, republish or roll back, manage channels and branches, and invite other users.

Overview

Is the app healthy right now?

listening
Online now
14,208
Devices
1.24M
Sessions
8.6M

Busiest in view

  • New York47.3k
  • Tokyo44.1k
  • Paris41.2k
  • London38.6k

ObserveOptional

The server implements the expo-observe protocol. Crashes, metrics, events and logs from every device come back tied to the update that produced them, and are written to your own ClickHouse.

Claudexprem mcp · oauth · rider
Ask about your app…

MCP server

An agent connected over MCP can list and manage updates, read their health and query expo-observe telemetry on the server.

Update 17849048644461

Published 24 Jul 2026 at 16:54:24

HealthAdoptionFaults

Successful devices across all attempts

iOS 95.1%

100%50%0%
18:0000:0006:0012:00

Update health

The server collects native and JS crashes to give each update a health status, readable from the dashboard or the MCP server.

rider1.2M
driver84k
admin3.1k

Multiple apps

One server hosts several apps. Each app has its own branches, channels, updates and health.

$ eoas publish$ eoas rollback$ eoas republish

Dedicated CLI

eoas publishes, rolls back and republishes from a terminal or a CI job.

ChannelproductionBranchproduction

Channels and branch mapping

A build carries a channel. The channel points at a branch, and repointing it changes what those builds receive without a new build.

25%

Progressive rollouts

An update can be published to a percentage of a branch. Each device is assigned by hashing its ID, so it stays on the same side between checks. The percentage can be raised, finished or reverted.

Full bundle2.1 MBbsdiff patch84 KB

Bundle diffingBeta · 3.2.0

A device that already holds a previous bundle downloads a bsdiff patch of the Hermes bytecode instead of the whole file. Patch size depends on how much the bundle changed.

Serverprivate-key.pemAppcertificate.pem

Code signing

The server signs every manifest it serves with a key shared with the app, so a device only applies updates that really come from your server.

Any CDNCDN_BASE_URLCloudflareAzure Front Door
CloudFrontsigned URLs, key pairCloudFront
Private bucket15-minute signed URLsGCSAzure Blob

CDN

Assets are served through the CDN you already run in front of the bucket, Cloudflare, Azure Front Door or any other, through CloudFront with signed URLs, or from a private bucket over short-lived signed URLs.

Cloudflare R2Google Cloud StorageAzure Blob Storage

Bucket storage

S3, Cloudflare R2, Google Cloud Storage, Azure Blob, Supabase Storage, MinIO, DigitalOcean Spaces or a local volume.

Entra IDGoogleOkta
RBACtoken: updates:writetenant: rider-co

EnterpriseEnterprise

SSO, role-based access control, scoped API tokens and custom device attributes.

Benchmarked: a million devices on one vCPU.

We replayed the update-check traffic of one million monthly active devices against a single vCPU for 18 minutes: 294,372 signed requests, zero errors, and a capacity probe that never found the saturation point. The k6 script, the method and the raw data are published.

Read the benchmark →
650 req/s

sustained on one vCPU, p95 1.39 ms

938 req/s

rollout burst absorbed, p95 20.5 ms

0 errors

294,372 requests, signing and telemetry on

Why self-host your OTA server.

EAS Update is the fastest way to get OTA updates running on a small app. The difference is who owns the data, the network and the source.

EAS UpdateExpo, hostedxpremself-hosted, open core
Your data livesOn their infrastructureIn your Postgres, ClickHouse and bucket
Private networkNeeds the public internetDeploys in your VPC or on-premise
SourceClosedMIT core, readable and forkable
If they disappearUnlikely, to be fairIt keeps running. You own it
GovernanceRetention and residency are theirsRetention, residency and access are yours
ScalingTheir capacity, their limitsYour replicas, your CDN, your regions
PricingPer monthly active userYour infrastructure bill. Nothing is metered

Questions.

The things people ask before they commit to running their own release infrastructure.

Does xprem only work with Expo?

It requires expo-updates in your app, yes. That is the protocol xprem implements, and it is what lets you keep the standard runtime instead of a proprietary client. expo-observe is separate: without it xprem still runs your releases, health and rollouts, you just do not get the events, metrics and logs. We bet on the Expo ecosystem on purpose. The packages are MIT, the community is large, and expo-updates is the default release path for React Native.

Do I need an Expo account?

Not in control plane mode. xprem holds the release metadata itself and authenticates publishing with a per-app API key. Stateless mode is the exception: it uses Expo as the source of truth and does need an Expo access token.

What do I have to run?

One Go process, a Postgres database and an object storage bucket. Add ClickHouse only when you want the full Observe layer. Everything ships as a single Docker image, a Helm chart or a static binary.

Do I have to change my app to migrate?

You point expo-updates at your own server URL and publish through the eoas CLI. The manifest, the asset download and the runtime behaviour are the standard protocol, so the client side of your app stays as it is.

Where do the update bundles live?

In your bucket. S3, Google Cloud Storage, Azure Blob, Cloudflare R2, MinIO, DigitalOcean Spaces, Supabase Storage, any S3-compatible provider, or a local volume. xprem writes to it and hands devices a URL into it.

How is it priced?

There is no per-user pricing. Nothing is metered, so unlimited devices and unlimited updates cost you the server, the database and the bucket you already run. The release engine is MIT. Observe is free to run; the source is in ee/, not MIT. SSO, RBAC, audit logs, token scopes, branch protection and custom device attributes need a commercial licence.

What is MIT and what is commercial?

Publishing, branches, channels, rollbacks, progressive rollouts, every storage backend, every CDN integration, the dashboard and the Prometheus metrics are MIT. Observe is free to run; the source is in ee/, not MIT. Enterprise adds SSO, RBAC, audit logs, token scopes and API key restrictions, branch protection, and custom device attributes, in the same binary. A feature released under MIT never moves behind the commercial licence.

Can I query the data with my own tools?

Yes. Observe writes into a ClickHouse you own, so you can point Grafana, Datadog, PostHog or plain SQL at it. Release state is in your Postgres. Nothing is locked behind an API we control.

Where are the xprem developer resources?

Start at xprem.dev/developers for the canonical links to the quickstart, Expo app configuration, eoas CLI, environment variables, source, releases, API-token guidance and MCP setup. Every self-hosted xprem server exposes its own /mcp endpoint; xprem.dev is not a shared control plane. Agents should read xprem.dev/agent-instructions.md before connecting so they choose the right deployment, begin with read-only discovery and confirm consequential release changes against the intended app, branch and channel.

How does xprem compare to EAS Update?

EAS Update is hosted by Expo and priced per monthly active user, and your update and device data lives on their infrastructure. xprem runs on yours: no metering, data in your own Postgres, ClickHouse and bucket, deployment on a private network, and per-update health, metrics, events and logs. EAS Update is the faster start for a small app; xprem is for teams that need to own the release path.

Is it affiliated with Expo?

No. xprem is an independent open-source project. It is not affiliated with, endorsed by, or supported by Expo (650 Industries, Inc.).

Is xprem the same project as expo-open-ota?

Yes. xprem is the new name of expo-open-ota: same codebase, same maintainers, same MIT core. The project was renamed because Expo is a trademark of 650 Industries and xprem is independent of it. Existing repository and documentation links keep working through the rename.

Everything above is covered in more depth in the documentation.