Expo OTA updates with Pakta
Configure the root layout, native channels and a Release build, then publish an update.
Updated 2026-09-15
On this page
Choose your Expo update workflow
This guide uses Pakta's rn-update client and pakta CLI for Expo OTA updates. If you are comparing expo-updates and EAS Update, first read Expo Updates vs Pakta. Moving from another OTA client requires a new native build with one system responsible for loading the bundle.
Prepare
Use a native Expo app, not Expo Go. This project's iOS automatic integration requires Expo 50 or later. Keep the existing compatible Expo/RN combination.
Install and select an application from the project root:
npx expo install rn-update
npm install -g rn-update-cli
pakta login
pakta selectApp --platform androidCreate an application in the console if needed, or run pakta createApp --platform android --name ExpoDemo. Select the matching ios application separately.
Wrap the root layout
For Expo Router, add the Provider to the existing app/_layout.tsx. This minimal Stack example must be merged with your theme, fonts and authentication setup:
import { Stack } from 'expo-router';
import { Platform } from 'react-native';
import { Pakta, UpdateProvider } from 'rn-update';
import updateConfig from '../update.json';
const configs = updateConfig as Record<string, { appKey: string }>;
const appKey = configs[Platform.OS]?.appKey;
if (!appKey) throw new Error(`Missing appKey for ${Platform.OS}`);
const client = new Pakta({ appKey, updateStrategy: 'silentAndLater' });
export default function RootLayout() {
return (
<UpdateProvider client={client}>
<Stack />
</UpdateProvider>
);
}For src/app/_layout.tsx, import ../../update.json. Without Expo Router, follow the standard root component setup.
Optional: set a channel
Skip this section for default. Create the custom channel in the console first. rn-update includes the Config Plugin; do not create a local plugin.
Add this entry to the existing expo.plugins array in app.json:
{
"expo": {
"plugins": [
["rn-update", { "channel": "staging" }]
]
}
}The channel is written to Android manifest metadata and iOS Info.plist. Use separate build configurations when Android and iOS need different channels. No plugin entry is needed for default.
Build and inspect
Run npx expo prebuild and verify channel in the generated Android manifest or iOS plist. EAS Build runs the same plugin.
npx expo run:android --variant releasenpx expo run:ios --configuration ReleaseAn existing EAS production workflow also works. Verify hot updates in the Release app.
Upload and publish
Retain the exact APK / IPA installed on the device and register it with
uploadApk/uploadIpa; see native registration.Change a screen label and build an update:
pakta bundle --platform android --expo --output .pakta/output/android.ppk --no-interactiveFollow first release, using the channel and version parsed from the native installer.
Check in the installed Release app, wait for download, fully close and reopen, then verify the changed label.
For iOS use --platform ios and a separate output path. Native plugins, channels and native SDK changes require a new installer, not just a .ppk.
