MainSDK
Search⌘K
Integrations

Expo

Use Expo for MainSDK push notifications and over-the-air app updates - EAS project, push credentials, main.yaml, testing and swapping.

2 interfaces2 driversWritten guide
Updated 2026-10-28

Expo is the toolkit and cloud service behind many React Native apps, and the MainSDK Expo adapter gives those apps the same interfaces as your web app. Expo serves two MainSDK interfaces. Its push service is a driver for notify: your server sends once, and Expo delivers through FCM on Android and APNs on iOS. Expo Updates is a driver for updates: it ships JavaScript-only fixes over the air and tells users when a store update is required. Pick Expo when your mobile app is built with Expo, so you manage one set of push credentials and one update channel.

Interfaces it serves

Pick Expo in main.yaml for any of these. Your calls stay the same, and you can swap later.

Before you start

You need an Expo account and an app set up with EAS (Expo Application Services).

  1. Link the app to an EAS project. Your app config holds the project ID that Expo's push and update services use.
  2. Give Expo your push credentials. Upload your FCM credentials for Android and your APNs key for iOS to EAS, so Expo can deliver to both. You still create those in Firebase and the Apple Developer Program.
  3. Optionally require an access token for push. Expo lets you require an access token on every push request, so a leaked push token alone can't be used to message your users. Turn it on for production.
  4. For updates: install expo-updates, set up update channels (for example preview and production) and a runtime version policy, so an update only reaches builds it is compatible with. Turn on update code signing so devices accept only updates you signed.

Store the access token and any signing key in your secrets manager, never in code or the app bundle.

Configure

Push through Expo:

main.yaml
notify:
  channels: [push, whatsapp, sms, email]
  push: { drivers: [fcm, apns], via: expo }

How the Expo driver takes its access token is not in the spec yet; it will be a secret: reference such as secret:EXPO_ACCESS_TOKEN (suggested name). A literal key fails validation with MAIN-CONFIG-0004.

Updates:

main.yaml
updates:
  driver: expo-updates

Use it

Register for push in the app, then notify from the server:

app/notifications/setup.ts
import { notify } from "mainsdk/notify";

await notify.push.register();   // asks permission, stores the token

await notify(user, { template: "order.shipped", category: "transactional" });

Check for a required update on startup:

app/startup.ts
import { updates } from "mainsdk";

export async function onStartup() {
  const u = await updates.check();
  if (u.required) showUpdateScreen(u);   // your own screen
}

Local development and testing

  • Push on a device: a development build registers a real Expo push token, so you can send test pushes before release.
  • Updates: publish to a preview channel and point a preview build at it before you publish to production.
  • Tests: createTestApp() from @mainsdk/testing runs notify and updates on in-memory fakes. chaos.on("notify", { outage: true }) simulates a push outage.

What MainSDK adds on top

  • Push only with opt-in, respecting opt-outs and quiet hours; no personal data in push payloads.
  • Updates are signed, and blocking an old version is enforced by the server as well as the app.
  • Blocked users can still export their data, and every change to the minimum version is audited.

See Notifications and App updates and version blocking.

Limits and notes

  • The notify:expo driver comes with the expo-adapter spec (phase 3, milestone 1.1). updates:expo-updates is listed for phase 2, with no spec yet; whether it ships with the adapter or earlier is an open question in that spec.
  • Over-the-air updates carry JavaScript and assets only. A change to native code needs a store build. On iOS, over-the-air changes must stay within Apple's rules.
  • Where device tokens are stored is not in the spec yet.
  • updates is free in your app; Cloud Teams adds release dashboards and Fleet adds fleet-wide version rules.

Swap to or from it

Send push to FCM and APNs directly instead of through Expo:

main.yaml
notify:
  push: { drivers: [fcm, apns] }   # was { drivers: [fcm, apns], via: expo }

FAQ

Do I still need Firebase and an Apple key with Expo? Yes. Expo delivers through FCM and APNs using credentials you upload to EAS, but your server only talks to Expo.

Can I fix a bug without a store review? For JavaScript-only changes, yes, with Expo Updates on Android, and on iOS where Apple's rules allow. Native changes need a store release.

Does Expo Updates block old versions by itself? No. MainSDK enforces the minimum version on the server too, so a modified client can't skip it.

Next

Open questions

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet