Skip to content

Environment Setup

Create .env from the root example file:

bash
cp .env.example .env

The API reads runtime configuration from the monorepo root .env first, then app-local environment where applicable.

Required server-side values

VariablePurpose
DATABASE_URLSupabase PostgreSQL pooler URL for API runtime queries
DATABASE_URL_DIRECTDirect PostgreSQL URL for migrations and verification
SUPABASE_URLSupabase project URL
SUPABASE_ANON_KEYSupabase anonymous key
SUPABASE_SERVICE_ROLE_KEYServer-only Supabase service-role key
SUPABASE_JWT_SECRETJWT verification secret
REDIS_URLRedis connection for BullMQ, OTP, sessions, and rate limits
ENCRYPTION_KEY64-character hex AES-256-GCM key for regulated data
ENCRYPTION_KEY_PREVIOUSOptional. The old key during a rotation — keeps rows written under it readable until they are re-encrypted or aged out by retention

eSIM feature lanes

The complete eSIM activation surface and the global eSIM store are controlled independently:

VariableUnset/default resolutionPurpose
FEATURE_ESIMtrueComplete eSIM activation: eSIM validation, activation creation, and QR/profile delivery. Set false to disable eSIM activation while physical-SIM activation remains available.
FEATURE_ESIM_STOREtrue outside production; false in productionGlobal eSIM store: catalog sync, browse, purchase, admin store operations, and FX refresh. Set explicitly to true or false when deployment behavior must not depend on NODE_ENV.

These are separate lanes: disabling FEATURE_ESIM does not disable the store, and disabling FEATURE_ESIM_STORE does not disable physical or complete-lane activation. In Docker Compose, both variables are passed to the API without a Compose-side default, so an unset value keeps the API resolution above.

VariableDefaultPurpose
ESIM_STORE_PROVIDERSmock-esim outside production, empty in productionComma-separated eSIM provider plugin keys the registry registers at boot. mock-esim is refused in production. An unknown key fails the boot. When the store flag is on and the resolved list registers nothing, the boot fails — an enabled store must never run without a provider.
MOBIMATTER_CALLBACK_URLnoneRequired HTTPS callback when ESIM_STORE_PROVIDERS includes mobimatter. Credentials are saved encrypted through Admin → Plugins, not environment variables.
MOBIMATTER_MAX_CONCURRENCY2Bounds concurrent MobiMatter calls (1-10). It does not add retries.
ESIM_SYNC_INTERVAL_MS300000Scheduled eSIM provider catalog refresh interval. Browse routes never call a provider catalog directly.

See MobiMatter eSIM Provider Operations for the safe deployment and live-test sequence.

FX rate values (defaults exist — required only conditionally)

VariablePurpose
FX_PROVIDERFX rate provider — mock (default) or exchangerate-api. mock is refused in production when the eSIM store is enabled.
EXCHANGE_RATE_API_KEYOptional, but required when FX_PROVIDER=exchangerate-api
FX_REFRESH_INTERVAL_MSFX rate refresh interval in milliseconds (default 86400000)

Local app ports

WorkspaceURL
apps/adminhttp://localhost:3000
apps/apihttp://localhost:3001
apps/web-b2chttp://localhost:3002
apps/sitehttp://localhost:3003

Set CORS_ORIGINS to include every frontend origin that calls the API.

Public frontend values

VariablePurpose
NEXT_PUBLIC_API_BASE_URLAPI URL exposed to Next.js browser bundles
NEXT_PUBLIC_SITE_URLPublic landing site URL for Next.js links
VITE_API_BASE_URLAPI URL exposed to Vite browser bundles
VITE_B2C_WEB_URLB2C web URL used by the landing site CTA
VITE_SITE_URLPublic landing site URL for Vite deployments

Never place secrets in NEXT_PUBLIC_* or VITE_* variables.

Internal documentation - Activation System