EAS Build
Prepare development, preview, production, and OTA builds with EAS.
EAS is the native distribution path for this Expo template. Use it for
development clients, internal preview builds, store builds, and OTA updates.
pnpm web is useful during development, but iOS and Android releases go
through EAS Build and EAS Submit.
Project wiring
app.config.ts includes the EAS project ID:
const EAS_PROJECT_ID = "3e167ef9-3e6c-47f2-9d14-01f738667145";The same file configures:
extra.eas.projectIdupdates.url = https://u.expo.dev/<project-id>runtimeVersion: { policy: "appVersion" }- variant-specific display name, bundle identifier, package name, and scheme
When you fork the template, replace the project ID with your own EAS project:
eas login
eas initThen commit the updated app.config.ts value.
Build profiles
eas.json ships three profiles:
| Profile | Distribution | Channel | Native details | Env |
|---|---|---|---|---|
development | Internal | development | developmentClient: true | APP_VARIANT=development, SENTRY_ENVIRONMENT=development |
preview | Internal | preview | Android APK, iOS device build, no iOS simulator | APP_VARIANT=preview, SENTRY_ENVIRONMENT=preview |
production | Store | production | autoIncrement: true | APP_VARIANT=production, SENTRY_ENVIRONMENT=production |
The CLI block uses:
{
"version": ">= 16.0.0",
"appVersionSource": "remote"
}Remote app version source means EAS owns build numbers. Use
eas build:version:get and eas build:version:set when you need to inspect or
manually adjust versions.
App variants
The template can install development, preview, and production builds side by side:
| Variant | Name | Bundle ID / package | Scheme |
|---|---|---|---|
| Development | Soar Starter (Dev) | expo.soarstarter.com.dev | soar-starter-expo-dev |
| Preview | Soar Starter (Preview) | expo.soarstarter.com.preview | soar-starter-expo-preview |
| Production | Soar Starter | expo.soarstarter.com | soar-starter-expo |
Run a local Metro session with the same variant:
pnpm dev
pnpm dev:preview
pnpm dev:prodUse matching .env.local, .env.preview, or your shell/EAS environment values
so the bundle gets the right Supabase project, RevenueCat keys, link domain, and
store URLs.
Environment and secrets
EXPO_PUBLIC_* values are public. They are inlined into the JavaScript bundle
and can be inspected by anyone with the app binary.
Put publishable client values in Expo/EAS env:
EXPO_PUBLIC_SUPABASE_URL=
EXPO_PUBLIC_SUPABASE_ANON_KEY=
EXPO_PUBLIC_REVENUECAT_IOS_KEY=
EXPO_PUBLIC_REVENUECAT_ANDROID_KEY=
EXPO_PUBLIC_POSTHOG_API_KEY=
EXPO_PUBLIC_SENTRY_DSN=Keep server secrets out of the client bundle:
| Secret | Where it belongs |
|---|---|
REVENUECAT_WEBHOOK_AUTH | Supabase Edge Function secret |
APNs keys for optional send-test-push | Supabase Edge Function secrets |
SENTRY_AUTH_TOKEN | EAS secret or CI secret for sourcemap upload |
| Supabase service role key | Never in Expo env; Supabase injects it into Edge Functions |
SENTRY_ENVIRONMENT is set per EAS build profile. Add SENTRY_AUTH_TOKEN when
you upload sourcemaps.
Build commands
Install a development client:
eas build --profile development --platform ios
eas build --profile development --platform androidCreate internal preview builds:
eas build --profile preview --platform ios
eas build --profile preview --platform androidCreate store builds:
eas build --profile production --platform ios
eas build --profile production --platform androidCloud builds are the normal path. Local builds are useful for debugging native configuration, but they still need local Xcode or Android tooling:
eas build --profile development --platform ios --local
eas build --profile development --platform android --localAfter installing a development build, start Metro:
pnpm devThen open the installed dev client. Expo Go can render many screens, but native modules such as purchases and Google Sign-In require a development or store build.
OTA updates
The template includes expo-updates:
runtimeVersion: { policy: "appVersion" },
updates: { url: "https://u.expo.dev/<project-id>" }Channels map to the EAS profiles:
| Channel | Build profile | Use |
|---|---|---|
development | development | Developer testing on dev clients |
preview | preview | Internal QA updates |
production | production | Store build updates |
Publish an OTA update to the matching channel:
eas update --channel preview --message "Fix onboarding copy"
eas update --channel production --message "Update paywall text"OTA can ship JavaScript, styling, copy, and assets bundled with the update. It cannot ship new native modules, config plugin changes, new permissions, bundle ID changes, or store metadata changes. Those require a new EAS build.
Because the runtime policy is appVersion, an OTA update only reaches builds
with the same app version. If an update does not arrive, check both channel and
runtime version first.
Submit teaser
Once a production build is ready, submit it to the stores:
eas submit --profile production --platform ios
eas submit --profile production --platform androidThe template's submit.production object is empty, so the first submit prompts
for store credentials and app selection. Store-specific preparation is covered
in Store Release.
