Skip to main content

How to use environment variables in SvelteKit (process.env)

It's easier than it used to be.

Published | Blog post

SvelteKit has recently changed how it brings environment variables into your code, whether from a .env file or from Node’s process.env. The new method is better. It allows you to bring private variables (secrets such as API keys) into server-side code without workarounds. Public variables can be imported into client-side code.

How

Four SvelteKit modules are at play to make this happen:

  1. $env/dynamic/public
  2. $env/dynamic/private
  3. $env/static/public
  4. $env/static/private

The dynamic modules are for variables accessed at runtime—variables not necessarily known at build time. The static modules for variables that can be injected as strings at build time. The public modules expose variables that are prefixed by “PUBLIC_” or another prefix set in your config file. The private modules expose variables not prefixed; trying to import them into client-side code will throw an error. That’s to keep you from accidentally exposing secrets to the front end. See the docs for more information.

In your DEV environment you can supply your public and private variables in a .env file. That file shouldn’t be committed to source control, especially if it has private variables. In a STAGE or PROD environment you’ll want to supply your environment variables through process.env by setting variables or secrets directly with your deployment service such as Vercel, Netlify, AWS Amplify, Azure Static Web Apps, or whatever yours is. This site, for instance, is hosted by GitHub Pages; its secrets are saved as repository secrets through the GitHub UI.

The docs show how to import the variables. For dynamic variables, you import env as a named export of the $env/dynamic/* module: import { dev } from '$env/dynamic/public';, for instance. Your variables are properties of the env object.

Static variables are imported directly as named exports from the $env/static/* module. This site, for instance, fetches content from Contentful during its build process. That requires API keys and other secrets and looks like this:

Embedded content: https://gist.github.com/ostermanj/aaeb966d4de44eb2a0d9e96c27987ce5

The (relatively) old way

The method outlined above came into being in July 2022, according to SvelteKit’s changelog. Before that, as best I understand, in local development SvelteKit was exposing variables loaded by Vite from .env, but only variables prefixed with “VITE_”. There was no straightforward way to import secrets into server-side code. One solution was to install env-cmd and add env-cmd to the dev script in package.json. That would expose the variables in .env to your source code but would make a detour around SvelteKit’s failsafe to prevent exposing secrets to the client.