JavaScriptDeveloper ToolsWeb Development

SvelteKit Explicit Env Vars: Migrate Before SvelteKit 3 Forces You

SvelteKit 2.63 shipped a quiet but consequential change: explicit environment variables, available today as an opt-in experimental flag. It is a preview of what SvelteKit 3 will require — and when SK3 lands, the $env/* modules you rely on today are gone. The new system is genuinely better. Migrating early is less painful than migrating all at once. Here is what changed, what replaces it, and whether you should move now.

The Old System Had Real Problems

The $env/* API was never bad, but it accumulated sharp edges over time. Three in particular are worth naming.

Autocomplete pollution. Typing any letter inside an import statement triggers suggestions for every environment variable on the host machine — not just your project’s variables, but also HOMEBREW_CELLAR, TERM_SESSION_ID, SHELL, and whatever else your OS exports. Rich Harris named this explicitly in PR #15934 as a primary motivation for the redesign. It is a minor annoyance that compounds into real friction on machines with hundreds of host env vars.

Naming collisions. If your code imports from both $env/dynamic/public and $env/dynamic/private, both default exports are named env. You have to alias one every time. It is a papercut that should not exist in a type-safe framework.

No startup validation. A missing required environment variable does not cause an error at startup — it causes a silent failure somewhere in a request handler, often surfacing as a cryptic 500 error in production. The only defense was manual validation code that most projects never wrote.

What Replaces What

The mapping is straightforward. The four $env/* modules collapse into two, and $app/environment gets renamed:

  • $env/static/private + $env/dynamic/private$app/env/private
  • $env/static/public + $env/dynamic/public$app/env/public
  • $app/environment$app/env

The static/dynamic distinction disappears from the import path. You declare your variables once in a central src/env.ts file, and SvelteKit handles whether they are baked in at build time or resolved at runtime based on your adapter and configuration.

How to Opt In Today

Enable the flag in svelte.config.js:

// svelte.config.js
export default {
  kit: {
    experimental: {
      explicitEnvironmentVariables: true
    }
  }
}

Then create src/env.ts and declare every variable your project uses:

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

export const variables = defineEnvVars({
  DATABASE_URL: { private: true },
  API_SECRET: { private: true },
  PUBLIC_API_URL: { public: true },
  PUBLIC_SITE_NAME: { public: true }
});

Update your imports. Old server code:

import { DATABASE_URL } from '$env/static/private';
import { building, browser } from '$app/environment';

Becomes this:

import { DATABASE_URL } from '$app/env/private';
import { building, browser } from '$app/env';

That is the full migration for a single file. For a whole project, it is a grep-and-replace with some judgment calls on the defineEnvVars declarations.

The Validation Upside Is the Real Reason to Migrate

defineEnvVars() runs at application startup, before any request is served. If a required variable is missing, the app crashes immediately with a clear error message — not silently, not during a request, not in production at 2 AM. That alone is worth the migration cost for most teams.

The secondary benefit is TypeScript type generation. Variables declared in src/env.ts are typed automatically. You get autocomplete on your actual project variables and nothing else. Public vs. private is now explicit in the declaration, not inferred from the PUBLIC_ prefix at import time. Accidental exposure of a private variable to the client becomes a build-time error rather than a runtime surprise.

Should You Migrate Now?

It depends on your project size.

For small projects — a handful of env vars across a few files — the migration takes under 30 minutes. Do it now. The flag is marked experimental, but the SvelteKit team uses it in production, and the API is stable enough that it is unlikely to change before SK3.

For large projects with dozens of environment variables spread across many server routes and hooks, this is a real refactor. Run grep -r '\$env/' src/ first to scope the work. Budget an afternoon, not a lunch break. The smart move is to migrate incrementally — new files use $app/env/*, old files get updated as you touch them.

SvelteKit 3 has no announced release date. There is time. But the window for incremental migration closes the longer you wait, and a big-bang migration when SK3 lands will hurt more than doing it in stages now. The full July 2026 SvelteKit release notes also cover the new option to define your SvelteKit config directly inside vite.config.js — another SK3 preview worth reading alongside this one.

Bottom Line

Explicit environment variables fix real problems: autocomplete noise, naming collisions, silent validation failures. The new system is more explicit, more type-safe, and more honest about what it does. The official SvelteKit environment variables documentation is already updated with the new API. Enable the experimental flag, create src/env.ts, and start migrating. SK3 will not punish you for doing this early — it will punish you for waiting.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:JavaScript