Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Environment variables: the $env modules

Environment variables are settings defined outside the code: a database address, a payment service key, the site name. Secrets must not be stored in the code or in git, and on a server the values often differ from your local ones. SvelteKit reads such variables through special $env modules.

The .env file

For development, variables are written to a .env file in the project root, next to package.json:

# .env
DATABASE_URL=postgres://localhost:5432/blog
API_KEY=secret-123
PUBLIC_SITE_NAME=My blog

The .env file is already listed in .gitignore of a project created with sv and does not get into the repository. After changing .env, restart npm run dev.

Secrets: $env/static/private

// src/lib/server/db.js
import { DATABASE_URL, API_KEY } from '$env/static/private';
 
export function connectionInfo() {
  return `Connecting to ${DATABASE_URL}, key length ${API_KEY.length}`;
}

The $env/static/private module can be imported only in server code: +page.server.js, +server.js, hooks.server.js, src/lib/server. If you import it in a component, the build stops with an error — the secret never goes to the browser.

Public values: $env/static/public

Variables whose names start with PUBLIC_ can be used in the browser too:

<!-- src/routes/+layout.svelte -->
<script>
  import { PUBLIC_SITE_NAME } from '$env/static/public';
 
  let { children } = $props();
</script>
 
<header>{PUBLIC_SITE_NAME}</header>
{@render children()}

The header of every page shows "My blog". Public variables are visible to any visitor in the page code — do not put anything secret into them.

Static and dynamic

ModuleWhen it is readWhere allowed
$env/static/privateat build timeserver only
$env/static/publicat build timeeverywhere
$env/dynamic/privatewhen the server startsserver only
$env/dynamic/publicwhen the server startseverywhere

Static values are inlined into the code during npm run build. If the values are set on the server at startup — for example, the same build runs against different databases — use a dynamic module:

// src/hooks.server.js
import { env } from '$env/dynamic/private';
 
export async function handle({ event, resolve }) {
  event.locals.maintenance = env.MAINTENANCE === 'on';
  return resolve(event);
}

In the dynamic modules the variables live in the env object and are read as its properties.

Common mistake

Reading variables through process.env.API_KEY. In development Vite does not load .env into process.env, so the value is undefined; in the browser there is no process at all. In a SvelteKit project always use the $env modules.

Thanks for reading!

Donate to the site — we work hard for you.