MuseMVP Docs
Configuration

Environment Variables

Find which settings you need now, where to put them, and what to configure before launch.

Use this page when you need to add a service or prepare a deployment. You do not need to fill every integration key to explore the local app with seed accounts.

Before You Start

Complete Quick Start. Init creates the local files and signing secrets for you. Keep your app's .env.example open as the field inventory, but put real values in .env.local, not the example file.

What to Configure Now

StageConfigure
First local sign-inGenerated auth/newsletter secrets; development Postgres; seed accounts
Brand customizationDefault locale, public support address, local site origin
Test email, OAuth, payment, or uploadOnly the credentials for the feature you are testing
DeployProduction origin, database/bindings, stable signing secrets, real mail, and every enabled integration

Local console mail does not deliver messages. Missing integrations can fail when used even though the homepage and seed login work. Product display settings live in packages/config/src/index.ts; credentials are environment values.

Application Environment

ConfigurationWeb
Local filesapps/web/.env.local
DatabaseDATABASE_URL; pooled Postgres
StorageS3-compatible S3_* credentials
Mailresend or cloudflare; local console
pnpm muse:init --yes --app web --database-url <postgres-url>
pnpm db:seed
pnpm dev

Init preserves existing values and generates missing signing secrets. Do not use --force on a configured environment.

Core Variables

VariablePurpose
NEXT_PUBLIC_SITE_URLOrigin, links, and OAuth callbacks; use the real production HTTPS origin
NEXT_PUBLIC_DEFAULT_LOCALEDefault en or zh
NEXT_PUBLIC_EMAIL_SUPPORTPublic support address
BETTER_AUTH_SECRETSession signing; missing in production runtime is a hard error
BETTER_AUTH_TRUSTED_ORIGINSComma-separated additional trusted origins
BETTER_AUTH_ENABLE_TEST_UTILSAutomated test helpers; keep false normally
GITHUB_CLIENT_ID/SECRET, GOOGLE_CLIENT_ID/SECRETOptional OAuth; missing credentials hide the provider
NEXT_PUBLIC_GOOGLE_ONE_TAP_CLIENT_IDOptional Google One Tap
NEXT_PUBLIC_TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEYBoth required to enable captcha
MAIL_FROM, MAIL_FROM_NEWSLETTER, CONTACT_FORM_TOTransactional/newsletter sender and contact inbox
NEWSLETTER_TOKEN_SECRETUnsubscribe HMAC signing, without an auth-secret fallback
MUSE_SEED_EMAIL, MUSE_SEED_PASSWORDLocal seed account domain and password, not production provisioning

Mail Credentials

Resend needs MAIL_PROVIDER=resend and RESEND_API_KEY. Cloudflare Email Sending needs CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN, and a verified sending domain. Local console prints messages without delivery and is rejected in production. Missing credentials can warn at startup but still break OTP delivery.

Billing

BILLING_DEFAULT_GATEWAY accepts muse_creem, muse_stripe, muse_dodo, or muse_waffo. Empty falls back across configured gateways. Never put secrets in NEXT_PUBLIC_*.

  • Creem: CREEM_API_KEY, CREEM_WEBHOOK_SECRET, CREEM_ENVIRONMENT
  • Stripe: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET
  • Dodo: DODO_PAYMENTS_API_KEY, DODO_PAYMENTS_WEBHOOK_SECRET, DODO_PAYMENTS_ENVIRONMENT
  • Waffo: WAFFO_MERCHANT_ID, WAFFO_PRIVATE_KEY, WAFFO_ENVIRONMENT; optional WAFFO_DEBUG, WAFFO_CUSTOMER_PORTAL_URL
  • Products: <GATEWAY>_PRODUCT_ID_PRO_MONTHLY, <GATEWAY>_PRODUCT_ID_PRO_YEARLY, <GATEWAY>_PRODUCT_ID_LIFETIME, with CREEM, STRIPE, DODO, or WAFFO prefixes

Store a Waffo private key on one line with \n for newlines. It signs API requests; webhooks use SDK verification, without a separate Waffo webhook secret. See gateway guides for sandbox/production environment values.

Object Storage

Set S3_ENDPOINT, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY. Optional settings are S3_AVATARS_BUCKET, S3_AVATARS_PROXY_URL, and S3_REGION. See storage.

Build and Runtime Boundaries

NEXT_PUBLIC_* values are inlined into clients and require a rebuild when changed. Inject server secrets on the target platform. Do not copy a whole local file containing seed credentials and development URLs into production.

src/env/readiness.ts collects errors/warnings, throws hard errors in production runtime, and does not abort the build phase for those same hard errors. Use SKIP_ENV_VALIDATION=true only for necessary secretless CI builds, never to hide missing production config. A successful build does not prove auth, mail, or database readiness.

Keep package ./env, the selected app schema, and .env.example aligned when adding variables. Platform differences are intentional. Never commit .env.local or real secrets.

Check Your Result

Restart the dev server after editing environment files. Production needs host secrets. Open the app and test the specific integration you enabled, such as a delivered email or sandbox checkout. Rebuild after changing NEXT_PUBLIC_* on a deployed app.

Common Problems

ProblemFix
Local settings changed but behavior did notCheck the selected app's file and restart its server
Live links still point at localhostCorrect the build-time public origin and rebuild
Production starts but a feature failsRead server/provider errors and check that feature's required values, not just build success

Follow Email, Payments, and Storage for service-specific walkthroughs.

On this page