pealdevDOCS
Back to peal.dev

AUTH STARTER · ENVIRONMENT VARIABLES

Environment variables

Every env var, why it exists, and what happens if it's missing. Validated with T3 Env + Zod — the app refuses to boot with a typo.

We don't read process.env directly anywhere except src/lib/env.ts. Every variable is declared there, validated by Zod on startup, and exported as a typed object. Typos are caught at boot, not at 2am in production.

Required (the app won't boot without these)

Terminal
# Database
DATABASE_URL="postgresql://user:pass@host/db?sslmode=require"

# Better Auth
BETTER_AUTH_SECRET="..."   # 32+ chars, openssl rand -base64 32
BETTER_AUTH_URL="http://localhost:3000"
NEXT_PUBLIC_APP_URL="http://localhost:3000"

Optional (features turn on when you fill them in)

Terminal
# Unpooled DB connection — used only by migrations
DATABASE_URL_UNPOOLED="postgresql://..."

# OAuth — Google
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""

# OAuth — GitHub
GITHUB_CLIENT_ID=""
GITHUB_CLIENT_SECRET=""

# Email (Resend) — required for magic links, OTP, password reset
RESEND_API_KEY=""
EMAIL_FROM="You <hello@yourdomain.com>"

# Captcha (Cloudflare Turnstile)
TURNSTILE_SECRET_KEY=""
NEXT_PUBLIC_TURNSTILE_SITE_KEY=""

Adding a new variable

Three steps, in this order:

  • Add it to src/lib/env.ts (server or client section + runtimeEnv mapping).
  • Add a placeholder to .env.example.
  • If secret → reference via env in auth.config.server.ts. If public → use process.env.NEXT_PUBLIC_* in auth.config.ts.

Why emptyStringAsUndefined matters

Hosting platforms (Vercel especially) often set undefined env vars as empty strings instead of leaving them undefined. We set emptyStringAsUndefined: true so optional vars don't fail Zod validation. If you add a NEW required string field, an empty value will be treated as missing — which is what you want.

process.env.X is forbidden everywhere except env.ts and the configs

Reading process.env.X directly bypasses validation. A typo silently passes. Always import { env } from "@/lib/env" so TypeScript and Zod have your back.