Skip to main content
General
Codebase

Environment Variables

Learn how environment variables are managed in the project.

Open MarkdownFull AI corpusFeedback

The starter kit uses @t3-oss/env-nextjs to manage environment variables with type safety and validation. All environment variables are defined in lib/env.ts with Zod schemas.

Environment Variable Files

Create a .env file in the root directory (you can copy from .env.example):

Terminal
cp .env.example .env

Use the same variable names in every environment, but store the values in the place that owns that environment:

EnvironmentWhere to set valuesWhat to commit
Local developmentRoot .env fileOnly .env.example with safe placeholders
Vercel or another hostThe project's environment variable settingsNothing containing production values
CIThe CI provider's encrypted secrets or variablesWorkflow references to the variable names

After changing a local value, restart the development server. After changing a hosted value, redeploy the affected environment so Next.js can include any build-time values in the new deployment.

Server and Browser Variables

The server and client schemas in lib/env.ts are a security boundary:

  • Server variables such as DATABASE_URL, BETTER_AUTH_SECRET, STRIPE_SECRET_KEY and RESEND_API_KEY must never use the NEXT_PUBLIC_ prefix.
  • Client variables must start with NEXT_PUBLIC_. Their values are included in browser-accessible JavaScript and must not contain credentials or secrets.
  • Adding a variable to .env does not add it to the validated application configuration. Declare it in the matching schema and in runtimeEnv as shown below.

Required Variables

The following environment variables are required for the application to run:

Database

.env
DATABASE_URL=postgresql://user:password@localhost:5432/dbname

Authentication

.env
BETTER_AUTH_SECRET=paste-a-new-random-secret-here

Generate a Better Auth secret

Generated locally with your browser's cryptographic random number generator. The value is never sent to Achromatic.

Add it to Paste the copied line into your local .env file and use a separately generated value in production.

Optional Variables

Build your environment template

Select only the integrations you plan to enable. This generates names and placeholders locally. It never asks for or stores credentials.

Generated `.env` template
# Required
DATABASE_URL="postgresql://user:password@localhost:5432/database"
BETTER_AUTH_SECRET="replace-with-a-generated-secret"
NEXT_PUBLIC_SITE_URL="http://localhost:3000"

Optional means the application can start without the integration. Once you enable a feature, configure its complete variable set rather than adding one key at a time.

FeatureConfigure togetherIf omitted
AI chatOPENAI_API_KEYAI requests cannot reach OpenAI
Google sign-inGOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRETGoogle is not offered as a sign-in method
Email deliveryEMAIL_FROM, RESEND_API_KEYEmail-sending flows fail when invoked
Stripe billingSTRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY and the Price IDs used by your configured plans or creditsBilling actions are unavailable
S3 storageS3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, NEXT_PUBLIC_IMAGES_BUCKET_NAMEUploads are unavailable
TurnstileTURNSTILE_SECRET_KEY, NEXT_PUBLIC_TURNSTILE_SITE_KEYCaptcha protection is disabled
Sentry source mapsSENTRY_ORG, SENTRY_PROJECT, SENTRY_AUTH_TOKENBuilds do not upload source maps

AI (OpenAI)

.env
OPENAI_API_KEY=sk-...

The shipped chat route uses the direct OpenAI provider. Its SDK reads OPENAI_API_KEY from the server environment, so this variable is intentionally not prefixed with NEXT_PUBLIC_. Remove the key if you disable the AI feature.

Authentication (OAuth)

.env
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

Billing (Stripe)

.env
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
NEXT_PUBLIC_STRIPE_PRICE_PRO_MONTHLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_PRO_YEARLY=price_...
NEXT_PUBLIC_STRIPE_PRICE_LIFETIME=price_...
NEXT_PUBLIC_STRIPE_PRICE_CREDITS_STARTER=price_...
NEXT_PUBLIC_STRIPE_PRICE_CREDITS_BASIC=price_...
NEXT_PUBLIC_STRIPE_PRICE_CREDITS_PRO=price_...

Email (Resend)

.env
EMAIL_FROM=noreply@example.com
RESEND_API_KEY=re_...

Storage (S3)

.env
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_ENDPOINT=https://your-s3-compatible-endpoint.example
S3_REGION=your-provider-region
NEXT_PUBLIC_IMAGES_BUCKET_NAME=your-bucket-name

Use the endpoint and signing region supplied by your storage provider. The storage client falls back to auto only when S3_REGION is omitted.

Monitoring (Sentry)

.env
SENTRY_ORG=your-org
SENTRY_PROJECT=your-project
SENTRY_AUTH_TOKEN=your-auth-token
NEXT_PUBLIC_SENTRY_DSN=https://...@sentry.io/...

Captcha (Cloudflare Turnstile)

.env
TURNSTILE_SECRET_KEY=your-secret-key
NEXT_PUBLIC_TURNSTILE_SITE_KEY=your-site-key

Site Configuration

.env
NEXT_PUBLIC_SITE_URL=https://your-domain.com
NEXT_PUBLIC_LOG_LEVEL=info

Type Safety

The project uses TypeScript and Zod to ensure type safety for environment variables. All variables are defined in lib/env.ts with validation schemas.

Adding New Variables

  1. Add the variable to lib/env.ts in the appropriate schema (server or client)
  2. Add the variable to .env.example (without sensitive values)
  3. Add the variable to your .env file with the actual value
  4. Add the variable to runtimeEnv in lib/env.ts
  5. Restart your development server

Example: Adding a Server Variable

lib/env.ts
server: {
  // ... existing variables
  MY_NEW_VAR: z.string().min(1),
},
lib/env.ts
runtimeEnv: {
  // ... existing variables
  MY_NEW_VAR: process.env.MY_NEW_VAR,
},

Example: Adding a Client Variable

Client variables must be prefixed with NEXT_PUBLIC_:

lib/env.ts
client: {
  // ... existing variables
  NEXT_PUBLIC_MY_VAR: z.string().optional(),
},
lib/env.ts
runtimeEnv: {
  // ... existing variables
  NEXT_PUBLIC_MY_VAR: process.env.NEXT_PUBLIC_MY_VAR,
},

Production

For production deployments, set environment variables in your hosting platform's dashboard (Vercel, Railway, etc.). Never commit production secrets to your repository.

Skipping Validation

For Docker builds or CI/CD pipelines, you can skip environment variable validation:

Terminal
SKIP_ENV_VALIDATION=true bun run build

This is useful when environment variables are provided at runtime rather than build time. It only skips schema validation. It does not supply missing values, so the related feature can still fail when used.