SsuperslateDocs

Configuration

Assign every product setting to the correct runtime boundary without exposing secrets.

Configuration

Configuration is owned by the layer that consumes it. The server validates private and deployment values once; the browser receives only intentionally public VITE_* values; deployment systems own their secret stores; provider dashboards own provider resources. Do not turn a local .env file into a second configuration authority.

The exact variables and defaults live in apps/server/.env.example and apps/web/.env.example. They are executable examples, while this page explains when a group is required and where it belongs.

Configuration map

ConcernCanonical ownerRequired whenKey examples
Database and runtimeServer environment validated in apps/server/src/config/env.tsAlwaysDATABASE_URL, pool limits, ENVIRONMENT, PORT
Identity and browser originServer environment and browser public environmentAlways outside local developmentBETTER_AUTH_SECRET, FRONTEND_URL, SERVER_URL, VITE_API_URL, TRUSTED_PROXY_PROFILE
Deployment identityDeployment environment and immutable release artifactA deployed API existsDEPLOYMENT_CLOUD, DEPLOYMENT_ENVIRONMENT, RELEASE_ID, IMAGE_DIGEST
Transactional emailServer environment and Resend accountProduction email is sentRESEND_API_KEY, EMAIL_FROM, EMAIL_TEMPLATES_DIR
BillingServer environment and exactly one provider dashboardPaid access is enabledBILLING_PROVIDER, selected provider credential, webhook secret, product IDs, display prices
Object storageServer environment and selected storage accountUploads are enabledSTORAGE_PROVIDER, bucket values, R2/S3/GCS credentials
OAuthServer environment and provider dashboardGoogle sign-in is enabledGOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, VITE_GOOGLE_CLIENT_ID
Observability and alertsServer or browser environment and selected serviceSentry or Slack is enabledSENTRY_PROJECT_IDS, browser VITE_SENTRY, build-only Sentry upload values, SLACK_BOT_TOKEN
Product identity and policiesSource-owned browser configuration and public environmentBefore real usersBRAND_NAME, VITE_TERMS_URL, VITE_PRIVACY_URL
Local-only demo sign-inLocal web environment and a local seeded accountDevelopment convenience onlyVITE_DEV_LOGIN_EMAIL, VITE_DEV_LOGIN_PASSWORD

VITE_* values are compiled into browser assets. They must never contain server credentials, webhook secrets, database URLs, private origins, or provider API keys.

Environment by purpose

EnvironmentPurposeRequired behavior
Local developmentBuild product behavior without third-party accountsPostgres and Better Auth work. Email uses the local log; billing, storage, Slack, Sentry, and Google remain visibly disabled unless configured completely.
TestProve isolated behavior in CI or a disposable databaseTest-only values, no external delivery, no shared database, and no production credentials.
StagingRehearse the exact deployment and provider boundarySeparate origins, database, secret store, and provider test/sandbox resources from production.
ProductionAccept real users and durable dataExact HTTPS origins, unique secret, selected proxy profile, verified sender, backup/restore proof, and complete live configuration for every enabled provider.

Do not point a preview deployment at the production API. Use a stable staging browser/API pair under the same registrable site when testing cookies.

Configure in dependency order

  1. Copy the two example environment files to ignored local files. Set only Postgres, the local Better Auth secret, and local origins first.
  2. Run the zero-key path from Setup. A local account, verification, reset, and magic link must work before adding provider credentials.
  3. Choose the production topology and set exact origins, proxy profile, deployment identity, and secret ownership as described in Deployment.
  4. Enable one optional capability at a time. Supply every value in its group, start the server, and run its failure and success smoke before enabling the next group.
  5. Record the variable owner, rotation owner, source dashboard, and last verified date in the deployment's private operations record. Record names and owners, never values, in tickets or release notes.

The add an environment variable path is required when you change the application configuration contract. It covers validation, examples, generation, deployment, documentation, and verification together.

Optional capability groups

CapabilityAll-or-nothing contractWhere to continue
BillingSelect polar, stripe, or dodo; provide that provider's credential, webhook secret, and at least one monthly or yearly product mapping. Leave the selected provider's integration values all unset for zero-key local work.Billing
StorageSelect one provider and provide the complete bucket, public URL, region, and matching credentials required by that provider.Object storage
GoogleProvide server client ID/secret, browser client ID, exact provider callback, and allowed origins together.Authentication
SentryProvide the public browser DSN and server allowlist together; build upload credentials belong only in CI or the protected build environment.Security
SlackProvide the server token only when sanitized operational alerts have a defined owner. Its absence is a valid disabled state.Notifications and marketing endpoints

Changing BILLING_PROVIDER after customers exist is not ordinary configuration. It requires an explicit entitlement migration and reconciliation plan; one deployment must not combine provider entitlements.

Safe configuration checks

The server fails at startup for invalid required values and partial selected billing or storage configuration. Validate the intended environment without printing secrets:

vp run --filter @app/server typecheck
vp run --filter @app/server test:unit
vp run --filter @app/server build

Then exercise the selected deployment's /ready endpoint and the enabled provider's real test or live smoke. Use Troubleshooting for the first observable failure instead of loosening origin, cookie, validation, or signature policy.

Values that must stay out of source control

Never commit real .env files, backend.hcl, .tfvars, state, cloud credentials, database URLs, webhook secrets, Better Auth secrets, OAuth secrets, provider API keys, signed URLs, or customer data. A name or public origin can be documented; a credential value cannot.

On this page