Skip to content

Environment variable reference

All environment variables for a client site are set in .env (local dev) or the Netlify site environment (production). The canonical source is .env.example in the repository root.

Columns:

  • Modealways = required regardless of auth provider; password = password-only auth; supabase = Supabase auth; cli = local migrations only, not needed at runtime.

VariableRequiredModeWhat reads itNotes
GITHUB_TOKENYesalways@drawnagency/githubFine-grained Personal Access Token (or GitHub App token). Needs read/write access to the contents and metadata scopes of GITHUB_REPO.
GITHUB_OWNERYesalways@drawnagency/githubGitHub organisation or username that owns GITHUB_REPO.
GITHUB_REPOYesalways@drawnagency/githubRepository name (without the owner prefix) where site content is stored.
SESSION_SECRETYesalways@drawnagency/primitives (session cookie signing) + @drawnagency/core middlewareRandom string, minimum 32 characters. Used to sign the session cookie in both password and Supabase modes. Generate with openssl rand -base64 32.
AUTH_PROVIDERNoalwaysAuth middleware"password" (default) or "supabase". Selects the active auth adapter.
ADMIN_PASSWORDYes (password mode)passwordPassword adapterBcrypt hash for the site-owner account. Escape every $ as \$ in .env (Vite’s dotenv-expand interprets bare $ as variable references and silently corrupts the hash).
EDITOR_PASSWORDYes (password mode)passwordPassword adapterBcrypt hash for editor accounts. Same escaping rules as ADMIN_PASSWORD.
VIEWER_<NAME>_PASSWORDNopasswordPassword adapterBcrypt hash for a named viewer audience (e.g. VIEWER_INTERNAL_PASSWORD). Add one per audience.
VIEWER_<NAME>_COLORNopasswordPassword adapterHex colour for a named viewer audience in the editor UI (e.g. VIEWER_INTERNAL_COLOR=#10b981).
SUPABASE_URLYes (supabase mode)supabase@drawnagency/auth-supabaseProject API URL, e.g. https://yourproject.supabase.co.
SUPABASE_ANON_KEYYes (supabase mode)supabase@drawnagency/auth-supabasePublic anon key. Safe to expose to the browser.
SUPABASE_SERVICE_ROLE_KEYYes (supabase mode)supabase@drawnagency/auth-supabaseService-role key. Server-only — never expose to the client. Used for admin operations (invite, delete, role assignment).
SUPABASE_ACCOUNT_TOKENNocliSupabase CLIPersonal access token for running supabase CLI commands (migrations). Not read at runtime. Obtain from the Supabase dashboard under Account → Tokens.
SUPABASE_PROJECT_REFNocliSupabase CLIProject reference (the <ref> segment of https://supabase.com/dashboard/project/<ref>). Not read at runtime.
SITEYessupabase@drawnagency/auth-supabaseCanonical origin of the deployed site, e.g. https://acme.drawn.guide. Used by Supabase auth to construct absolute URLs in invite and password-reset emails. Not in .env.example — provisioner-pinned in Netlify’s environment variables. Only read by @drawnagency/auth-supabase; not needed in password-only mode. For sites provisioned before this was added, set it manually in Netlify’s environment variables.

Bcrypt hashes contain $ characters. Vite processes .env with dotenv-expand, which interprets $name as a variable reference and strips it, silently corrupting the hash. Always escape every $ with a backslash:

# bcryptjs output:
# $2b$10$n1JHs0z5qYC.ISZGabc...
# Write in .env as:
ADMIN_PASSWORD=\$2b\$10\$n1JHs0z5qYC.ISZGabc...

Quoting the value does not prevent expansion. Only \$ works.


Custom env vars (everything except Vite builtins like PROD, DEV, SSR) are not injected into import.meta.env in the Netlify Functions SSR runtime. All @drawnagency/* packages that read env vars use this pattern:

const value =
import.meta.env?.[key] ??
(typeof process !== "undefined" ? process.env?.[key] : undefined) ??
"";

The typeof process guard is required because portal.config.mjs and its imports can be loaded in the browser during editor hydration, where process is undefined. If you add a new env var read in any @drawnagency/* package, always include both the import.meta.env lookup and the guarded process.env fallback.