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
| Variable | Public | What it is |
|---|---|---|
VITE_SUPABASE_URL | Yes | The public address of the Supabase API gateway |
VITE_SUPABASE_PUBLISHABLE_KEY | Yes | The anonymous key the browser authenticates with |
VITE_SUPABASE_PROJECT_ID | Yes | Project 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:
| Variable | What it controls |
|---|---|
SERVICE_PASSWORD_JWT | The secret every JWT in the system is signed with |
SERVICE_SUPABASESERVICE_KEY | The service-role key, which bypasses row-level security entirely |
SERVICE_PASSWORD_POSTGRES | The database superuser password |
ENABLE_EMAIL_AUTOCONFIRM | Whether sign-ups skip email verification |
DISABLE_SIGNUP | Whether 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.