Configuration

Configure Expo environment keys, app variants, links, app config, and service fallbacks.

Expo configuration happens in two places:

  • .env.local or an environment-specific file provides public client keys.
  • app.config.ts builds the native config, app identifiers, URL schemes, permissions, plugins, and EAS update metadata.

The config chain

Start from .env.example

cp .env.example .env.local

Use .env.development, .env.preview, and .env.production when you want separate values per build environment.

Expo inlines EXPO_PUBLIC_*

Every EXPO_PUBLIC_* value is bundled into the JavaScript that ships to users. Treat these values as public: publishable Supabase anon keys, RevenueCat public SDK keys, PostHog project keys, and Sentry DSNs are fine; service-role keys, webhook secrets, APNs private keys, and Sentry auth tokens are not.

Providers read their own keys

Supabase is required for auth/data/storage. Optional providers check their keys: RevenueCat reports unconfigured, PostHog disables capture, Sentry disables SDK capture, update gates stay quiet, and links fall back to Expo-created URLs.

app.config.ts builds the native app config

The dynamic config derives display name, bundle/package ID, URL scheme, native permissions, plugins, associated domains, Android intent filters, EAS project ID, runtime version, and update URL.

Server-only values belong outside the JS bundle. Put REVENUECAT_WEBHOOK_AUTH and APNs keys in Supabase Edge secrets; put SENTRY_AUTH_TOKEN in EAS secrets or CI. Do not expose them as EXPO_PUBLIC_*.

Starter .env.local

# Supabase
EXPO_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_PROJECT_ID=your-project-ref

# Optional providers
EXPO_PUBLIC_REVENUECAT_IOS_KEY=
EXPO_PUBLIC_REVENUECAT_ANDROID_KEY=
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID=
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID=
EXPO_PUBLIC_POSTHOG_API_KEY=
EXPO_PUBLIC_SENTRY_DSN=
APP_VARIANT=development

Restart the Expo dev server after changing EXPO_PUBLIC_* values. Rebuild a development client after changing native identifiers, plugins, permissions, or URL scheme behavior.

Key reference

Supabase

Prop

Type

RevenueCat

Prop

Type

lib/purchases.tsx never configures RevenueCat on web. The app still reads entitlement from Supabase through useEntitlement().isEntitled; RevenueCat CustomerInfo is purchase/cache state, not the gate.

Google Sign-In

Prop

Type

Google Sign-In is native-only. The optional module is not loaded on web, and the button reports configuration errors when required IDs are missing.

PostHog

Prop

Type

Sentry

Prop

Type

Version gate

Prop

Type

Prop

Type

App variant

Prop

Type

App variants

app.config.ts derives identifiers from APP_VARIANT so development, preview, and production builds can install side by side:

VariantApp nameBundle / package IDURL scheme
developmentSoar Starter (Dev)expo.soarstarter.com.devsoar-starter-expo-dev
previewSoar Starter (Preview)expo.soarstarter.com.previewsoar-starter-expo-preview
productionSoar Starterexpo.soarstarter.comsoar-starter-expo

The EAS profiles in eas.json set the same variant names:

  • development uses a development client, internal distribution, and the development channel.
  • preview uses internal distribution, Android APK output, and the preview channel.
  • production uses store distribution, auto-increments versions, and the production channel.

Dynamic native config

Keep native app settings in app.config.ts, not in a static app.json. The template currently configures:

  • newArchEnabled: true and Android edgeToEdgeEnabled: true.
  • iOS and Android bundle identifiers from the active variant.
  • scheme from the active variant.
  • iOS associatedDomains and Android intentFilters when EXPO_PUBLIC_LINKING_DOMAIN is set.
  • expo-router, expo-splash-screen, expo-apple-authentication, @react-native-google-signin/google-signin, expo-tracking-transparency, and Sentry plugins.
  • Camera, photos, notification, ATT, and Apple Sign-In permission/capability metadata.
  • EAS project id, runtimeVersion: { policy: "appVersion" }, and the expo-updates URL.

On this page