Skip to content

Environment variables

Copy .env.example to .env and fill in the values before running the dev server or deploying. All variables listed here are read at runtime by the Netlify function — none are baked into the static build.

VariableRequiredDescription
GITHUB_TOKENYesFine-grained personal access token with read/write access to the client repo’s Contents, plus the mandatory read-only Metadata permission. Scoped to the single client repository.
GITHUB_OWNERYesGitHub organization or username that owns the client repo.
GITHUB_REPOYesRepository name (without the owner prefix).
VariableRequiredDescription
SESSION_SECRETYesRandom string used to sign session cookies. Must be at least 32 characters. Generate one:
Terminal window
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
VariableRequiredDescription
AUTH_PROVIDERNopassword (default) or supabase. Omit to use password-only auth.

Used when AUTH_PROVIDER=password (or AUTH_PROVIDER is unset). All *_PASSWORD values are bcrypt hashes, not plaintext.

VariableRequiredDescription
ADMIN_PASSWORDYes (password mode)Bcrypt hash for the site owner account.
EDITOR_PASSWORDYes (password mode)Bcrypt hash for editor accounts.
VIEWER_<NAME>_PASSWORDNoBcrypt hash for a named viewer audience. <NAME> becomes the audience name (e.g. VIEWER_INTERNAL_PASSWORD). Optional — add one per gated viewer audience.
VIEWER_<NAME>_COLORNoHex color for the named audience badge in the editor UI (e.g. VIEWER_INTERNAL_COLOR=#10b981).
Terminal window
node -e "console.log(require('bcryptjs').hashSync('your-password', 10))"

Critical — escape every $ in the hash with a backslash. Vite runs dotenv-expand, which interprets $name as a variable reference and silently strips it, corrupting the hash. Quoting the value does NOT prevent this; only \$ does.

# bcryptjs gives you:
$2b$10$n1JHs0z5qYC.ISZG...
# Write in .env as:
ADMIN_PASSWORD=\$2b\$10\$n1JHs0z5qYC.ISZG...

Second gotcha: no leading whitespace before the key name. dotenv silently skips indented lines, so every sign-in attempt will fail with “Invalid password” — with no error in the logs.

Used when AUTH_PROVIDER=supabase.

VariableRequiredDescription
SUPABASE_URLYes (supabase mode)Your Supabase project URL, e.g. https://your-project.supabase.co.
SUPABASE_ANON_KEYYes (supabase mode)Supabase anon (public) key. Safe to include in the build.
SUPABASE_SERVICE_ROLE_KEYYes (supabase mode)Supabase service role key. Server-only — never expose to the client.

The optional SUPABASE_ACCOUNT_TOKEN and SUPABASE_PROJECT_REF variables are only needed when running Supabase migrations via the CLI (pnpm db:push) — they are not required at runtime.

VariableRequiredDescription
SITEYes (Supabase mode, production)The canonical origin of the site, e.g. https://acme.drawn.guide. Required in Supabase mode — used by invite and password-reset emails. Not needed in password-only mode. Set in the Netlify dashboard, not in .env.

SITE must be pinned to the custom domain — not the *.netlify.app subdomain. It is used by invite and password-reset emails. Netlify’s built-in URL environment variable can resolve to the Netlify subdomain instead of the custom domain, so an explicit SITE is required.

This variable is set by the provisioner when creating the site. For existing sites built before this was introduced, set it manually in the Netlify dashboard and trigger a redeploy.

For the exhaustive list of every variable and its validation rules, see the Environment variable reference.