# Environment

> Validated Supabase settings, with every framework spelling and no leaked values.

Source: https://bettersupabase.com/docs/auth/env

```ts
import { loadEnv, publicEnv } from "better-supabase/env";

const env = loadEnv(); // reads process.env, throws EnvValidationError
const browser = publicEnv(env); // { url, publishableKey }, safe to ship
```

`loadEnv()` accepts the spellings frameworks use, the first one set wins:

| Setting          | Variables                                                                                                   |
| ---------------- | ----------------------------------------------------------------------------------------------------------- |
| `url`            | `SUPABASE_URL`, with `NEXT_PUBLIC_`, `VITE_`, `PUBLIC_`, `EXPO_PUBLIC_`, `NUXT_PUBLIC_`                     |
| `publishableKey` | `SUPABASE_PUBLISHABLE_KEY` (same prefixes), `SUPABASE_PUBLISHABLE_DEFAULT_KEY`, `SUPABASE_PUBLISHABLE_KEYS` |
| `secretKey`      | `SUPABASE_SECRET_KEY`, `SUPABASE_SECRET_KEYS`                                                               |
| `dbUrl`          | `SUPABASE_DB_URL`, `DATABASE_URL`                                                                           |
| `jwksUrl`        | `SUPABASE_JWKS_URL`, else derived from `url`                                                                |
| `jwks`           | `SUPABASE_JWKS`: inline keys as `{"keys":[...]}` or `[...]`, used instead of fetching `jwksUrl`             |
| `readUrl`        | `SUPABASE_READ_URL`, a [read replica](/docs/guides/read-replicas) API URL (server only)                     |
| `jwtSecret`      | `SUPABASE_JWT_SECRET`, the HS256 secret [Supabase Lite](/docs/platform/lite) signs with (server only)       |

## What is checked [#what-is-checked]

* The URL is `https`, or `http` on `localhost`, `127.0.0.1` or `[::1]` only.
* Keys use the new format: `sb_publishable_…` and `sb_secret_…`. Legacy
  `eyJ…` JWT keys are rejected with a pointer to the API Keys settings.
* A secret key in a publishable variable is an error, not a warning.
* `SUPABASE_JWKS` is JSON with at least one key that has a `kty`, read the
  way `@supabase/server` reads it.
* `SUPABASE_JWT_SECRET` has at least 32 characters. Only `backend: 'lite'`
  reads it.
* `require: ['secretKey', 'dbUrl']` makes optional settings mandatory.
* `SUPABASE_PUBLISHABLE_KEYS` and `SUPABASE_SECRET_KEYS` must be JSON objects
  of key names to keys. All secret keys are kept in `env.secretKeys` (the
  single key is `default`), so a server can accept
  [named keys](/docs/auth/server#machine-callers).

Error messages name the variables and never include their values, so they
are safe to log.

## Standard Schema [#standard-schema]

`envSchema()` is the same validator as a [Standard Schema](https://standardschema.dev),
for t3-env, framework config or any other validator slot:

```ts
import { envSchema } from "better-supabase/env";

const result = await envSchema({ require: ["secretKey"] })[
  "~standard"
].validate(process.env);
```

## With `@supabase/server` [#with-supabaseserver]

`toServerEnv(env)` returns the `SupabaseEnv` that `withSupabase({ env })`
and the `@supabase/server` core functions take.

> **Client bundles**
>
> Next.js only inlines `NEXT_PUBLIC_*` variables that are read literally. In
> browser code, pass them explicitly:
> `loadEnv({ NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL, … })`.