Svelte logo

SvelteKit by Example: Environment Variables & Secrets

Environment variables keep configuration separate from source code. Some values, like database credentials, must stay on the server.

In this example, we'll configure a todo service and give our app a public name.

SvelteKit 3 uses $app/env/private and $app/env/public instead of the older $env/* modules. Declare each variable in src/env.js, then import it by name.

Variables are private and read at runtime by default. Keep the todo service token private.

Mark only browser-safe values as public. static: true fixes the app name at build time; changing it requires a rebuild.

src/env.js
import { defineEnvVars } from '@sveltejs/kit/env';

export const variables = defineEnvVars({
  TODO_API_TOKEN: {},
  TODO_API_URL: {},




  APP_NAME: { public: true, static: true },
});

Set local values in .env.local. These are placeholders, not real credentials. Keep secret files out of version control.

.env.local
TODO_API_TOKEN=replace-with-your-service-token
TODO_API_URL=https://todos.example.com
APP_NAME=My todos

Private imports belong in server-only code. Never return the token from load, log it, or put it in rendered HTML.

Send the token only to your trusted service. This example expects its /todos endpoint to return a JSON array of todos.

src/routes/todos/+page.server.js
import { TODO_API_TOKEN, TODO_API_URL } from '$app/env/private';
import { error } from '@sveltejs/kit';

/** @type {import('./$types').PageServerLoad} */
export async function load({ fetch }) {


  const response = await fetch(`${TODO_API_URL}/todos`, {
    headers: { Authorization: `Bearer ${TODO_API_TOKEN}` },
  });

  if (!response.ok) error(502, 'Could not load todos.');
  return { todos: await response.json() };
}

Public variables can be imported by components. Anyone using the app can read them: a public variable is never a secret.

src/routes/+page.svelte
<script>
  import { APP_NAME } from '$app/env/public';
</script>

<h1>{APP_NAME}</h1>

Deployment

Development and builds read .env files. In production, supply runtime secrets through your hosting provider. Node's production server doesn't automatically read .env files; use deployment environment variables or node --env-file=.env build.

On Cloudflare, configure variables and secrets on the Worker. Prefer $app/env/* for environment variables; use cloudflare:workers for bindings such as KV or D1, not process.env.

Runtime values need a server adapter. Prerendering runs load at build time and publishes its returned data, so it cannot fetch fresh todos on each visit. For a live page, disable prerendering with export const prerender = false in +page.js.