Skip to content

Environment variables

How they reach the application

Variables prefixed with VITE_ are read by Vite at build time and inlined into the JavaScript bundle that ships to the browser. They are public by definition. Anyone who opens the site can read them out of the page source, so nothing secret may ever carry a VITE_ prefix.

Everything else is read at runtime, on the server, and never reaches the browser.

This distinction is not cosmetic. It determines whether a value is a secret or a published fact, and getting it wrong is how credentials leak.

What the application reads

VariablePublicWhat it is
VITE_SUPABASE_URLYesThe public address of the Supabase API gateway
VITE_SUPABASE_PUBLISHABLE_KEYYesThe anonymous key the browser authenticates with
VITE_SUPABASE_PROJECT_IDYesProject identifier, used for storage URLs

The publishable key being public is expected and safe. It identifies the project; it grants no privilege by itself. Everything it can do is constrained by row-level security, which is why those policies matter so much.

Server-side values

The Supabase stack itself reads a much larger set of variables, defined in the deployment platform rather than in this repository. The ones worth knowing about:

VariableWhat it controls
SERVICE_PASSWORD_JWTThe secret every JWT in the system is signed with
SERVICE_SUPABASESERVICE_KEYThe service-role key, which bypasses row-level security entirely
SERVICE_PASSWORD_POSTGRESThe database superuser password
ENABLE_EMAIL_AUTOCONFIRMWhether sign-ups skip email verification
DISABLE_SIGNUPWhether new accounts can be created at all

Two of these deserve particular care.

The service-role key ignores every row-level security policy. Code holding it can read and write anything. It belongs only in server-side code, loaded lazily inside server handlers so it never ends up in a client bundle by accident.

The JWT secret signs every session token. Anyone holding it can mint a token for any user, including an owner. Rotating it invalidates every active session and signs everybody out, so it is disruptive to change and therefore worth protecting properly.

Build-time exposure

When the deployment platform is told a variable is needed at build time, it writes that variable into the generated build definition, where it becomes visible in build logs and in the resulting image's metadata.

Only the three VITE_ variables genuinely need to be available during the build. Everything else should be marked as runtime-only. Marking a secret as build-time available is the specific mistake that put credentials into build logs on this project once already.

There is no committed template

The repository has no .env.example. There should be one: a file listing every variable name with a comment explaining what it is, and no real values.

Until it exists, a new contributor has no way to discover what the application needs except by reading source code or asking. If you are setting up for the first time and find yourself guessing, adding that file is a genuinely useful first contribution.

Whatever you do, never commit a real .env. The repository ignores it, and it must stay that way.

Internal engineering documentation.