SkillByAIOpen interactive version →

Lesson 21 / 25

Environment Variables With $env

Static, dynamic, public and private.

Four $env modules

SvelteKit exposes environment variables through four modules. $env/static/private and $env/static/public are inlined at build time, which enables dead-code elimination; $env/dynamic/private and $env/dynamic/public are read at run time, which suits values that differ between deployments of the same build. Only variables starting with the public prefix (PUBLIC_ by default) can be imported from the public modules and reach the browser. Private modules can only be imported in server-only code; importing them into client code is a build error. Locally, values come from .env files loaded by Vite; in production, from the platform.

Using the right module

Server secret and public base URL.

// .env (not committed)
// DATABASE_URL=postgres://...
// STRIPE_SECRET_KEY=sk_test_...
// PUBLIC_API_BASE=https://api.example.com

// src/lib/server/db.ts  (server-only)
import { DATABASE_URL } from '$env/static/private';
import { createClient } from './driver'; // your database client library
export const db = createClient(DATABASE_URL);

// src/routes/+page.server.ts
import { env } from '$env/dynamic/private';
const featureFlag = env.FEATURE_NEW_CHECKOUT === 'true';

// src/lib/api.ts  (can run in the browser)
import { PUBLIC_API_BASE } from '$env/static/public';
export const api = (path: string) => fetch(`${PUBLIC_API_BASE}${path}`);

A safe and a notice board

Private variables stay in the server-room safe; only notes marked PUBLIC_ are pinned on the notice board that every visitor can read.

Quick check: Which variable can be imported into code that runs in the browser?

  • DATABASE_URL from $env/static/private
  • PUBLIC_API_BASE from $env/static/public
  • Any variable from $env/dynamic/private
  • process.env.SECRET_KEY
Answer

PUBLIC_API_BASE from $env/static/public — Only public-prefixed variables reach the client.