Environment variables

Per-project secrets encrypted at rest and injected into every preview container at start.

Setting variables

Open a project and click the Variables tab. Add a key/value pair, save, then redeploy — the next build has the new env. No rebuild of existing previews; variables are read when the container boots.

Values are encrypted
Every value is encrypted with AES-256-GCM before it hits the database. The dashboard decrypts server-side only for the owning workspace. Ciphertext never reaches the browser. If the encryption key rotates and a value fails to decrypt, the field shows blank rather than raw ciphertext so you can safely re-enter it.

Built-in variables

PreviewDrop sets these for every container, on top of whatever you add:

VariableWhat it holds
PORTTCP port your app must listen on. Do not hardcode a port — this value changes per container.
NEXTAUTH_URLAutomatically set to the live preview URL. NextAuth / Auth.js picks this up with no extra config.
AUTH_URLSame as NEXTAUTH_URL — set for frameworks that use AUTH_URL instead.

Per-branch overrides

Every variable has a default value (applies to every preview) and can optionally be overridden per branch. Use this when you want the main branch pointed at a staging DB but feature branches pointed at an isolated one.

In the Variables tab, click the ellipsis next to a variable and choose Add override → pick the branch pattern. Branch patterns support exact matches (main) and globs (feature/*).

Importing and exporting

Paste a .env file directly into the Variables tab with Import from .env. Export is the inverse — a signed, time-limited download so you can move config between projects without passing secrets through Slack.

Secrets-in-Git? Don't.

Don't commit secrets
PreviewDrop builds and runs whatever's in your repo, including .envfiles if you commit them. Secrets committed to Git are already leaked — PreviewDrop can't un-leak them. Put real secrets only in the Variables tab.

Common recipes

Branch-isolated databases with Neon

Neon branch integration
# Default (trunk): use a shared staging DB DATABASE_URL=postgres://u:p@ep-shared.neon.tech/app # Override for feature/*: Neon creates a branch DB per git branch # Set via Neon's GitHub integration, then reference the secret here DATABASE_URL=${NEON_BRANCH_DB_URL}

Auth callbacks (NextAuth / Auth.js)

NextAuth / Auth.js
# NEXTAUTH_URL and AUTH_URL are set automatically — no variable needed. # Add *.previews.previewdrop.dev as an allowed redirect URI in your OAuth provider.

CORS for a separate frontend calling a preview API

Django / Rails / Express
# Hardcode the preview subdomain pattern in your CORS config: ALLOWED_ORIGINS=https://*.previews.previewdrop.dev

Feature flag SDK key scoped to previews

GrowthBook / LaunchDarkly
# Use a dedicated preview-env SDK key so flag changes don't affect production LD_SDK_KEY=sdk-preview-...

Debugging a missing variable

If your app can't see a variable you set, try in order:

  • Redeploy the preview — variables are injected at container start, not hot-reloaded.
  • Check the build log for typos in your ENV directives. A hardcoded ENV PORT=8080 in the Dockerfile overrides PreviewDrop's injected PORT.
  • Confirm there's no branch override shadowing your value — branch overrides win over defaults.

If a variable still looks blank in the Variables tab after you saved it, it may have failed to decrypt (encryption key rotation, envelope corruption). Re-enter the value; the next save re-encrypts under the current key.