Browse docs
Getting Started

Environment Setup

The two .env files, what each key does, and why every paid integration runs green without one.

Updated Jul 2026
On this page

There are two env files, both gitignored, both created for you by node scripts/init-env.mjs.

apps/mobile/.env — the app

Everything here is prefixed EXPO_PUBLIC_ and is inlined into the JS bundle at build time, so treat these as publishable, not secret.

EXPO_PUBLIC_API_URL=http://localhost:3000
EXPO_PUBLIC_AUTH_PROVIDER=custom-jwt   # custom-jwt | clerk | better-auth
EXPO_PUBLIC_AUTH_ENABLED=true          # false = no-login app
# Optional integrations — leave blank to no-op:
EXPO_PUBLIC_POSTHOG_KEY=
EXPO_PUBLIC_SENTRY_DSN=
EXPO_PUBLIC_REVENUECAT_IOS_KEY=

Env changes need a restart

EXPO_PUBLIC_* values are baked in at bundle time. After editing them, restart the Expo dev server — hot reload won't pick them up.

apps/api/.env — the backend

Server secrets that never ship to the client:

JWT_SECRET=            # generated by init-env
ACCESS_TOKEN_TTL=900
REFRESH_TOKEN_TTL=2592000
DATABASE_URL=          # SQLite by default
ALLOWED_ORIGINS=RESEND_API_KEY=         # password-reset emails; optional

The "no key required" rule

Every paid integration — Sentry, PostHog, RevenueCat, Stripe, Clerk, Resend, Google Maps — no-ops when its key is missing. That's deliberate: the app runs green on a fresh clone, and you add keys one integration at a time.

Testing on a real device

Set EXPO_PUBLIC_API_URL=http://<your-LAN-IP>:3000 and restart the dev server so your phone can reach the backend.

Want everything wired up?

Get the full Mobile App Boilerplate — auto-update, code-signing, license activation, AI primitives, 26 UI components — for $59.

Get it for $59 →