Builds & Releases
The mobile app ships through EAS Build and EAS Submit, not through the Kubernetes cluster.
Why you cannot use Expo Go
The app depends on native modules that Expo Go does not include:
@livekit/react-native-webrtc— voice and video roomsexpo-notifications— push@bugsnag/expo— crash reportingreact-native-purchases— in-app purchases
You need a development build: a custom binary containing the app's native modules, which then loads your JavaScript from Metro. Install it once and iterate on JS normally.
Build profiles
apps/mobile/eas.json defines three:
| Profile | Distribution | Environment | Points at |
|---|---|---|---|
development | internal, iOS simulator | development | http://localhost:4000 / :4010 |
preview | internal | staging | staging-api.playpalz.gg / staging-socket.playpalz.gg |
production | store | production | api.playpalz.gg / socket.playpalz.gg |
The environment variables baked into each profile determine what the binary talks to. production sets autoIncrement: true, so the build number rises automatically.
appVersionSource: "remote" means EAS owns the build number, not the repo — do not hand-edit it.
App identity
| Value | |
|---|---|
| Slug | playpalz |
| iOS bundle id | com.playpalzinc.playpalz |
| Android package | com.playpalzinc.playpalz |
| Version | 1.0.0 (app.json) |
app.config.ts overrides the display name and URL scheme per environment on top of app.json:
EXPO_PUBLIC_ENV | Name | Scheme |
|---|---|---|
development | PlayPalz Dev | playpalz-dev |
staging | PlayPalz Staging | playpalz-staging |
production | PlayPalz | playpalz |
Per-environment bundle identifiers are commented out
app.config.ts contains commented-out bundleIdentifier and package overrides. As it stands, all three environments share one identifier, so a dev, staging, and production build cannot coexist on one device — installing one replaces another. Uncommenting them (and registering the extra ids with Apple and Google) is what makes side-by-side installs possible.
Building
npm i -g eas-cli
eas login
cd apps/mobile
eas build --profile development --platform ios
eas build --profile preview --platform all
eas build --profile production --platform allA development build for the simulator (ios.simulator: true) produces a .app you drag onto a running simulator. Device builds need the device UDID registered.
Submitting
eas submit --profile production --platform ios # → App Store Connect / TestFlight
eas submit --profile production --platform android # → Google PlayConfig plugins
app.json declares the plugins that shape the native project:
| Plugin | Purpose |
|---|---|
expo-router | File-based routing |
expo-splash-screen | Splash, background #160b2d |
expo-video | Background playback and picture-in-picture |
expo-image-picker | Photo library and camera |
@config-plugins/react-native-webrtc | WebRTC native setup |
@livekit/react-native-expo-plugin | LiveKit native setup |
app.config.ts additionally injects the notification usage description on iOS and the NOTIFICATIONS, VIBRATE, and RECEIVE_BOOT_COMPLETED permissions on Android.
Changing a plugin requires a new build. Config plugins run at prebuild time and modify native projects; a Metro reload will not pick them up.
Native change checklist
You need a new development build whenever you:
- Add or remove a native dependency
- Change a config plugin or its options
- Change the bundle identifier, app name, or scheme
- Change permissions or Info.plist entries
- Upgrade the Expo SDK
You do not need one for JavaScript, styling, or asset changes.
Crash reporting
Bugsnag is initialised in app/_layout.tsx, and only outside development:
if (process?.env.EXPO_PUBLIC_ENV !== "development") {
const Bugsnag = require("@bugsnag/expo").default;
Bugsnag.start();
}The lazy require is deliberate — Bugsnag pulls in @react-native-community/netinfo, whose native module is missing in development, and a static import would throw before the module finished evaluating.
package.json also wires eas-build-on-success to npx bugsnag-eas-build-on-success, which uploads source maps so production stack traces are readable.
The Bugsnag API key is committed
BUGSNAG_API_KEY appears in plaintext in apps/mobile/eas.json. Bugsnag notifier keys are client-side by design and are not a serious secret, but move it to an EAS secret rather than the repo if you would rather not have it in git history.
Release checklist
pnpm check-typesandpnpm lintpass.- Backend changes the release depends on are deployed and migrated.
versioninapp.jsonbumped for a user-visible release.eas build --profile production --platform all.- Smoke-test the resulting build via TestFlight / internal track: login, feed, post with an image, DM, a voice room, a purchase.
eas submit --profile production --platform all.- Watch Bugsnag for a spike after rollout.
Local development builds
You can also build locally if you have the toolchains:
cd apps/mobile
npx expo run:ios
npx expo run:androidSlower than EAS the first time and it requires a working Xcode / Android Studio setup, but it does not consume EAS build minutes and gives you native logs directly.
