FrançaisPlayground

Environment variables

Which values reach the browser is declared, not spelled. An app lists the public ones in fluixi.config.ts; everything else stays on the server, whatever it is called.

// fluixi.config.ts
import { defineConfig } from '@fluixi/start/config';

export default defineConfig({
  env: {
    public: ['AUTH_ISSUER', 'AUTH_CLIENT_ID', 'AUTH_TOKENS', 'API_URL', 'APP_URL'],
  },
});

Vite's convention puts the decision in the name: a VITE_ prefix publishes the value. Moving a value between server and browser then renames every reference, and a secret named VITE_API_SECRET ships whether anything reads it or not. A list means a secret can only reach the bundle by being written into it.

Reading them

import { publicEnv, serverEnv } from '@fluixi/start/env';

const { API_URL } = publicEnv();                                    // anywhere
const secret = serverEnv('SESSION_SECRET', { required: true });     // server only

publicEnv() works on both sides and returns the same frozen set on each. In the browser the build has defined it as a literal. On the server it reads process.env, narrowed to the same declared names, so a loader cannot use a value the browser will not have. It also works when the server imports @fluixi/start from node_modules instead of bundling it, which is the default for a published install: there import.meta.env is undefined, and code reading it breaks in production only.

serverEnv(name) reads one server-only variable. In a browser it throws instead of returning undefined, because a secret read as undefined becomes a request sent without credentials, and the failure then points at the request instead of at the read. { required: true } also throws when the variable is unset, naming it.

Where the values come from

fluixi dev and fluixi start load .env, .env.local, .env.<mode> and .env.<mode>.local into process.env on the server, every variable, prefixed or not. A variable already set in the real environment wins over the files, which is how a deployment's own secrets override a developer's .env.

The VITE_ prefix

It keeps working. A declared name is found under its bare spelling or with VITE_ in front, bare first, so .env can move one variable at a time: AUTH_ISSUER in env.public reads VITE_AUTH_ISSUER until it is renamed. Anything already prefixed stays public, as it always was.

What stops a secret shipping

The list is the protection. Three checks catch the line written in a hurry:

Check When What happens
a name in env.public reads like a secret (SECRET, PASSWORD, PRIVATE_KEY, CREDENTIALS) build refused, naming it
a VITE_ variable in any .env file reads like a secret fluixi build refused; fluixi dev warns
serverEnv() called in the browser run time throws

For a name that only reads like a secret, FLUIXI_ALLOW_PUBLIC_SECRETS=true lets the build through.

Next: SEO and the document head.