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.
PREVIEWDROP_URLThe full public preview URL (e.g. https://feature-abc.previews.previewdrop.dev).
PREVIEWDROP_BRANCHGit branch name being previewed.
PREVIEWDROP_COMMITFull commit SHA being built.
PREVIEWDROP_PROJECTProject ID (handy for logging / analytics).

Use PREVIEWDROP_URL for anything that needs the public origin — OAuth callbacks, CORS, email links to reviewers, feature-flag targeting.

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 that follow the preview URL

Auth0 / Clerk / NextAuth
NEXTAUTH_URL=${PREVIEWDROP_URL} AUTH_REDIRECT_URL=${PREVIEWDROP_URL}/callback

CORS that only trusts the preview

Django / Rails / Express
ALLOWED_ORIGINS=${PREVIEWDROP_URL}

Feature flags scoped to the branch

GrowthBook / LaunchDarkly
FEATURE_FLAG_ENV=${PREVIEWDROP_BRANCH} # LaunchDarkly SDK key for a preview-only project 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.