ProjectR Docs
Mobile

Environment

env.js validation, APP_ENV, and production invariants.

Single source of truth: env.js

env.js loads .env.{APP_ENV} (files: .env.development, .env.staging, .env.production — all gitignored), then zod-validates client and buildTime schemas separately. It is the only file that reads dotenv; EXPO_NO_DOTENV=1 is set on every script and every EAS profile so Expo's own dotenv loading never races it.

Client code imports from @env; app.config.ts imports env.js directly.

Variable groups

  • Backend selection: CONVEX_DEPLOYMENT, CONVEX_URL, CONVEX_SITE_URL (prod uses the appsapi/appsbackend.theraw.com.my custom domains).
  • Identity: APP_ENV, NAME, SCHEME, BUNDLE_ID, PACKAGE (non-prod builds get suffixed bundle ids via withEnvSuffix).
  • Integrations: SHOPIFY_STORE_URL, SHOPIFY_STOREFRONT_ACCESS_TOKEN, Google client IDs (web/iOS/Android), SENTRY_DSN plus the Sentry environment and sample rates that env.js derives from APP_ENV.
  • Misc: EAS_PROJECT_ID, SUPPORT_WHATSAPP/SUPPORT_EMAIL, notification flags, PRODUCT_QUERY_LIMIT, MMKV_OBFUSCATION_KEY (obfuscation, not encryption).

Production invariants

PRODUCTION_ENV_INVARIANTS in env.js pins, when APP_ENV=production: the bundle/package/scheme, the prod Convex URLs, and the three Google client IDs — any drift throws at config time. A second guard throws if a development env points at prod Convex URLs unless ALLOW_DEV_ON_PROD_CONVEX=1.

Sentry sample rates differ per environment (prod traces 0.2, profiles 0.1).

On this page