Environment & secrets
Golden rules
- .env.local and similar files belong in
.gitignore. Commit only.env.examplewith placeholder values. - Prefix public browser vars with
NEXT_PUBLIC_only when unavoidable; prefer server-side config for secrets. - Use GitHub Environments (Staging / Production) so CI injects different secrets per branch without mixing prod DB into staging builds.
Layers
Local development
Minimal .env: database URL, auth secret, maybe Stripe test keys. Use Stripe CLI for webhooks.
Staging (e.g. develop branch)
Staging DB, test Stripe mode or separate test products, Resend sandbox or domain-restricted sending.
Production
Live keys, live webhook endpoints, monitored Resend domain, Firebase production project for push.
Example shape (landing / checkout slice)
For the marketing site with Stripe checkout + Neon orders:
# App
NEXT_PUBLIC_APP_URL=https://yourdomain.com
# Stripe
STRIPE_SECRET_KEY=sk_...
STRIPE_PRICE_ID=price_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Database
DATABASE_URL=postgresql://...
# Email / product copy
RESEND_API_KEY=re_...
RESEND_FROM_EMAIL="SigmaNext <[email protected]>"
PRODUCT_NAME=SigmaNext
# GitHub collaborator invite (optional)
GIT_REPO_FULL_NAME=org/private-repo
GIT_TOKEN=ghp_...Neon DATABASE_URL in Docker / CoolifyDo not wrap
DATABASE_URL in single or double quotes in panel env vars (unlike some .env examples). The Neon serverless driver uses new URL(); a leading ' makes the string invalid and webhooks fail to save orders. The app normalizes common quote-wrapping; prefer pasting the raw postgresql://... URL.Docker build-argsIf you bake env into images via CI, pass secrets as build-args only in trusted pipelines (GitHub Actions with Environment protection). Prefer runtime env injection for truly secret values when possible.