From 4bf0b7b7e6f0845decc5c6d4206d1accdfa5c419 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Mon, 13 Jul 2026 22:09:35 +0200 Subject: [PATCH 1/4] feat: reinstate `$app/environment` and `$env/*` for backwards compatiblity It is deprecated on a type level and prints a warning in dev, but it otherwise still usable. That way people have an easier time incrementally updaing to SvelteKit 3, and are no longer blocked on libraries that use the old imports, waiting for them to update to the new imports. --- .changeset/legacy-env-imports.md | 5 ++ packages/kit/src/core/env.js | 47 +++++++++++++++++++ packages/kit/src/core/sync/write_env.js | 10 ++-- packages/kit/src/exports/vite/index.js | 2 + .../kit/src/runtime/app/environment/index.js | 6 +-- .../kit/src/runtime/env/dynamic/private.js | 7 +++ .../kit/src/runtime/env/dynamic/public.js | 7 +++ .../kit/src/runtime/env/static/private.js | 6 +++ packages/kit/src/runtime/env/static/public.js | 6 +++ .../src/routes/env/legacy/+page.server.js | 9 ++++ .../basics/src/routes/env/legacy/+page.svelte | 13 +++++ packages/kit/test/apps/basics/test/test.js | 18 +++++++ 12 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 .changeset/legacy-env-imports.md create mode 100644 packages/kit/src/runtime/env/dynamic/private.js create mode 100644 packages/kit/src/runtime/env/dynamic/public.js create mode 100644 packages/kit/src/runtime/env/static/private.js create mode 100644 packages/kit/src/runtime/env/static/public.js create mode 100644 packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js create mode 100644 packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte diff --git a/.changeset/legacy-env-imports.md b/.changeset/legacy-env-imports.md new file mode 100644 index 000000000000..4ca3ffec668b --- /dev/null +++ b/.changeset/legacy-env-imports.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +feat: reinstate `$env/static/private`, `$env/dynamic/private`, `$env/static/public`, `$env/dynamic/public` and `$app/environment` as deprecated aliases for `$app/env/private` `$app/env/public` and `$app/env` diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index 63c493e61875..321d20ad5ba6 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -323,6 +323,53 @@ export function create_explicit_env_types(variables, relative, type) { `; } +/** + * Creates type declarations for the legacy `$env/static/*` and `$env/dynamic/*` modules, + * which re-export from `$app/env/*`. + * @param {Record>} variables + * @param {string} relative + * @param {EnvType} type + */ +export function create_legacy_env_types(variables, relative, type) { + const entries = Object.entries(variables) + .filter(([_, config]) => !!config.public === (type === 'public')) + .map(([name, config]) => { + const comment = config.description ? `${create_jsdoc(config.description)}\n` : ''; + const var_type = config.schema + ? `import('@sveltejs/kit/internal/types').StandardSchemaV1.InferOutput` + : 'string'; + return { name, comment, var_type }; + }); + + const static_declarations = entries + .map( + ({ name, var_type }) => + `/** @deprecated This variable was imported from the deprecated '$env/static/${type}' module. Import it from '$app/env/${type}' instead */\nexport const ${name}: ${var_type};` + ) + .join('\n'); + + const dynamic_properties = entries + .map(({ name, var_type }) => `${name}: ${var_type};`) + .join('\n'); + + const empty = `// no ${type} environment variables were defined`; + + return dedent` + /** @deprecated Use \`$app/env/${type}\` instead */ + declare module '$env/static/${type}' { + ${static_declarations || empty} + } + + /** @deprecated Use \`$app/env/${type}\` instead */ + declare module '$env/dynamic/${type}' { + /** @deprecated Importing env.* from the '$env/dynamic/${type}' module is deprecated. Import it from '$app/env/${type}' instead */\n + export const env: { + ${dynamic_properties || empty} + }; + } + `; +} + export const reserved = new Set([ 'do', 'if', diff --git a/packages/kit/src/core/sync/write_env.js b/packages/kit/src/core/sync/write_env.js index 1a6946a81982..d26eb60d39dd 100644 --- a/packages/kit/src/core/sync/write_env.js +++ b/packages/kit/src/core/sync/write_env.js @@ -1,6 +1,6 @@ /** @import { EnvVarConfig } from '@sveltejs/kit' */ import path from 'node:path'; -import { create_explicit_env_types } from '../env.js'; +import { create_explicit_env_types, create_legacy_env_types } from '../env.js'; import { write_if_changed } from './utils.js'; import { posixify } from '../../utils/os.js'; @@ -23,13 +23,17 @@ export function write_env(kit, entry, env_config) { content.push( `// This file is generated from ${relative}.\n${DOCS}`, create_explicit_env_types(env_config, relative, 'private'), - create_explicit_env_types(env_config, relative, 'public') + create_explicit_env_types(env_config, relative, 'public'), + create_legacy_env_types(env_config, relative, 'private'), + create_legacy_env_types(env_config, relative, 'public') ); } else { content.push( DOCS, create_explicit_env_types({}, '', 'private'), - create_explicit_env_types({}, '', 'public') + create_explicit_env_types({}, '', 'public'), + create_legacy_env_types({}, '', 'private'), + create_legacy_env_types({}, '', 'public') ); } diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 56479d7ebe1d..f3d69b9957ca 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -97,6 +97,7 @@ const enforced_config = { resolve: { alias: { $app: true, + $env: true, $lib: true, '$service-worker': true } @@ -386,6 +387,7 @@ function kit({ svelte_config }) { alias: [ { find: '__SERVER__', replacement: `${generated}/server` }, { find: '$app', replacement: `${runtime_directory}/app` }, + { find: '$env', replacement: `${runtime_directory}/env` }, ...get_config_aliases(kit, root) ] }, diff --git a/packages/kit/src/runtime/app/environment/index.js b/packages/kit/src/runtime/app/environment/index.js index d57e433f52fa..573ed729d892 100644 --- a/packages/kit/src/runtime/app/environment/index.js +++ b/packages/kit/src/runtime/app/environment/index.js @@ -1,6 +1,6 @@ -import { dev } from '../env/index.js'; +import { DEV } from 'esm-env'; export * from '../env/index.js'; -if (dev) { - console.warn('`$app/environment` is now `$app/env`'); +if (DEV) { + console.warn('`$app/environment` is deprecated, use `$app/env` instead'); } diff --git a/packages/kit/src/runtime/env/dynamic/private.js b/packages/kit/src/runtime/env/dynamic/private.js new file mode 100644 index 000000000000..d1875571ac66 --- /dev/null +++ b/packages/kit/src/runtime/env/dynamic/private.js @@ -0,0 +1,7 @@ +import { DEV } from 'esm-env'; +import * as env from '../../app/env/private.js'; +export { env }; + +if (DEV) { + console.warn('`$env/dynamic/private` is deprecated, use `$app/env/private` instead'); +} diff --git a/packages/kit/src/runtime/env/dynamic/public.js b/packages/kit/src/runtime/env/dynamic/public.js new file mode 100644 index 000000000000..1c77e1e80b83 --- /dev/null +++ b/packages/kit/src/runtime/env/dynamic/public.js @@ -0,0 +1,7 @@ +import { DEV } from 'esm-env'; +import * as env from '../../app/env/public/index.js'; +export { env }; + +if (DEV) { + console.warn('`$env/dynamic/public` is deprecated, use `$app/env/public` instead'); +} diff --git a/packages/kit/src/runtime/env/static/private.js b/packages/kit/src/runtime/env/static/private.js new file mode 100644 index 000000000000..27beb05e7236 --- /dev/null +++ b/packages/kit/src/runtime/env/static/private.js @@ -0,0 +1,6 @@ +import { DEV } from 'esm-env'; +export * from '../../app/env/private.js'; + +if (DEV) { + console.warn('`$env/static/private` is deprecated, use `$app/env/private` instead'); +} diff --git a/packages/kit/src/runtime/env/static/public.js b/packages/kit/src/runtime/env/static/public.js new file mode 100644 index 000000000000..b5fc00d88707 --- /dev/null +++ b/packages/kit/src/runtime/env/static/public.js @@ -0,0 +1,6 @@ +import { DEV } from 'esm-env'; +export * from '../../app/env/public/index.js'; + +if (DEV) { + console.warn('`$env/static/public` is deprecated, use `$app/env/public` instead'); +} diff --git a/packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js new file mode 100644 index 000000000000..441c55a76bf0 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js @@ -0,0 +1,9 @@ +import { PRIVATE_STATIC } from '$env/static/private'; +import { env as dynamic_private } from '$env/dynamic/private'; + +export function load() { + return { + PRIVATE_STATIC, + PRIVATE_DYNAMIC: dynamic_private.PRIVATE_DYNAMIC + }; +} diff --git a/packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte new file mode 100644 index 000000000000..0c3fc4146873 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte @@ -0,0 +1,13 @@ + + +

PRIVATE_STATIC: {data.PRIVATE_STATIC}

+

PRIVATE_DYNAMIC: {data.PRIVATE_DYNAMIC}

+ +

PUBLIC_STATIC: {PUBLIC_STATIC}

+

PUBLIC_DYNAMIC: {dynamic_public.PUBLIC_DYNAMIC}

diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index b6dac3ac1f07..5d3092fc7be5 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -210,6 +210,24 @@ test.describe('$app/env', () => { 'PUBLIC_DYNAMIC: accessible anywhere/evaluated at run time' ); }); + + test('legacy $env/* imports still work', async ({ page }) => { + await page.goto('/env/legacy'); + + expect(await page.textContent('#static-private')).toBe( + 'PRIVATE_STATIC: accessible to server-side code/replaced at build time' + ); + expect(await page.textContent('#dynamic-private')).toBe( + 'PRIVATE_DYNAMIC: accessible to server-side code/evaluated at run time' + ); + + expect(await page.textContent('#static-public')).toBe( + 'PUBLIC_STATIC: accessible anywhere/replaced at build time' + ); + expect(await page.textContent('#dynamic-public')).toBe( + 'PUBLIC_DYNAMIC: accessible anywhere/evaluated at run time' + ); + }); }); test.describe('Load', () => { From 09047fa026eed3c69dab28809873c8e9a27c7c24 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Mon, 13 Jul 2026 23:10:35 +0200 Subject: [PATCH 2/4] adjust docs --- documentation/docs/20-core-concepts/70-environment-variables.md | 2 +- documentation/docs/98-reference/20-$app-environment.md | 2 +- documentation/docs/98-reference/25-$env-dynamic-private.md | 2 +- documentation/docs/98-reference/25-$env-dynamic-public.md | 2 +- documentation/docs/98-reference/25-$env-static-private.md | 2 +- documentation/docs/98-reference/25-$env-static-public.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/docs/20-core-concepts/70-environment-variables.md b/documentation/docs/20-core-concepts/70-environment-variables.md index d785468585c0..c98ec820950e 100644 --- a/documentation/docs/20-core-concepts/70-environment-variables.md +++ b/documentation/docs/20-core-concepts/70-environment-variables.md @@ -17,7 +17,7 @@ After following the setup below, they can be imported via the following modules: - [`$app/env/public`]($app-env-public) > [!LEGACY] -> The `$env/*` modules, along with `$app/environment` were removed in SvelteKit 3 in favour of explicit environment variables that were added in SvelteKit 2.62 as an experimental option. +> The `$env/*` modules, along with `$app/environment` were deprecated in SvelteKit 3 (and will be removed in SvelteKit 4) in favour of explicit environment variables that were added in SvelteKit 2.62 as an experimental option. ### Setup diff --git a/documentation/docs/98-reference/20-$app-environment.md b/documentation/docs/98-reference/20-$app-environment.md index 196d3061d844..2968e7f45367 100644 --- a/documentation/docs/98-reference/20-$app-environment.md +++ b/documentation/docs/98-reference/20-$app-environment.md @@ -2,4 +2,4 @@ title: $app/environment --- -This module was removed in SvelteKit 3 in favour of [$app/env]($app-env). +This module was deprecated in SvelteKit 3 in favour of [$app/env]($app-env). It will be removed in SvelteKit 4. diff --git a/documentation/docs/98-reference/25-$env-dynamic-private.md b/documentation/docs/98-reference/25-$env-dynamic-private.md index 127493349119..72b7391d4881 100644 --- a/documentation/docs/98-reference/25-$env-dynamic-private.md +++ b/documentation/docs/98-reference/25-$env-dynamic-private.md @@ -2,4 +2,4 @@ title: $env/dynamic/private --- -This module was removed in SvelteKit 3 in favour of [explicit environment variables](environment-variables). +This module was deprecated in SvelteKit 3 in favour of [explicit environment variables](environment-variables). It will be removed in SvelteKit 4. diff --git a/documentation/docs/98-reference/25-$env-dynamic-public.md b/documentation/docs/98-reference/25-$env-dynamic-public.md index 1f495fd66cd1..793995e9ba96 100644 --- a/documentation/docs/98-reference/25-$env-dynamic-public.md +++ b/documentation/docs/98-reference/25-$env-dynamic-public.md @@ -2,4 +2,4 @@ title: $env/dynamic/public --- -This module was removed in SvelteKit 3 in favour of [explicit environment variables](environment-variables). +This module was deprecated in SvelteKit 3 in favour of [explicit environment variables](environment-variables). It will be removed in SvelteKit 4. diff --git a/documentation/docs/98-reference/25-$env-static-private.md b/documentation/docs/98-reference/25-$env-static-private.md index ae16f1389960..19b14e4e2ce1 100644 --- a/documentation/docs/98-reference/25-$env-static-private.md +++ b/documentation/docs/98-reference/25-$env-static-private.md @@ -2,4 +2,4 @@ title: $env/static/private --- -This module was removed in SvelteKit 3 in favour of [explicit environment variables](environment-variables). +This module was deprecated in SvelteKit 3 in favour of [explicit environment variables](environment-variables). It will be removed in SvelteKit 4. diff --git a/documentation/docs/98-reference/25-$env-static-public.md b/documentation/docs/98-reference/25-$env-static-public.md index d55ec39cb150..7e936817d3d5 100644 --- a/documentation/docs/98-reference/25-$env-static-public.md +++ b/documentation/docs/98-reference/25-$env-static-public.md @@ -2,4 +2,4 @@ title: $env/static/public --- -This module was removed in SvelteKit 3 in favour of [explicit environment variables](environment-variables). +This module was deprecated in SvelteKit 3 in favour of [explicit environment variables](environment-variables). It will be removed in SvelteKit 4. From 6f4764a3e0ad1527be4e57125079d858838d96de Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Wed, 15 Jul 2026 23:36:36 +0200 Subject: [PATCH 3/4] remove type generation --- packages/kit/src/core/env.js | 47 ------------------- packages/kit/src/core/sync/write_env.js | 10 ++-- .../src/routes/env/legacy/+page.server.js | 2 + .../basics/src/routes/env/legacy/+page.svelte | 2 + 4 files changed, 7 insertions(+), 54 deletions(-) diff --git a/packages/kit/src/core/env.js b/packages/kit/src/core/env.js index 321d20ad5ba6..63c493e61875 100644 --- a/packages/kit/src/core/env.js +++ b/packages/kit/src/core/env.js @@ -323,53 +323,6 @@ export function create_explicit_env_types(variables, relative, type) { `; } -/** - * Creates type declarations for the legacy `$env/static/*` and `$env/dynamic/*` modules, - * which re-export from `$app/env/*`. - * @param {Record>} variables - * @param {string} relative - * @param {EnvType} type - */ -export function create_legacy_env_types(variables, relative, type) { - const entries = Object.entries(variables) - .filter(([_, config]) => !!config.public === (type === 'public')) - .map(([name, config]) => { - const comment = config.description ? `${create_jsdoc(config.description)}\n` : ''; - const var_type = config.schema - ? `import('@sveltejs/kit/internal/types').StandardSchemaV1.InferOutput` - : 'string'; - return { name, comment, var_type }; - }); - - const static_declarations = entries - .map( - ({ name, var_type }) => - `/** @deprecated This variable was imported from the deprecated '$env/static/${type}' module. Import it from '$app/env/${type}' instead */\nexport const ${name}: ${var_type};` - ) - .join('\n'); - - const dynamic_properties = entries - .map(({ name, var_type }) => `${name}: ${var_type};`) - .join('\n'); - - const empty = `// no ${type} environment variables were defined`; - - return dedent` - /** @deprecated Use \`$app/env/${type}\` instead */ - declare module '$env/static/${type}' { - ${static_declarations || empty} - } - - /** @deprecated Use \`$app/env/${type}\` instead */ - declare module '$env/dynamic/${type}' { - /** @deprecated Importing env.* from the '$env/dynamic/${type}' module is deprecated. Import it from '$app/env/${type}' instead */\n - export const env: { - ${dynamic_properties || empty} - }; - } - `; -} - export const reserved = new Set([ 'do', 'if', diff --git a/packages/kit/src/core/sync/write_env.js b/packages/kit/src/core/sync/write_env.js index d26eb60d39dd..1a6946a81982 100644 --- a/packages/kit/src/core/sync/write_env.js +++ b/packages/kit/src/core/sync/write_env.js @@ -1,6 +1,6 @@ /** @import { EnvVarConfig } from '@sveltejs/kit' */ import path from 'node:path'; -import { create_explicit_env_types, create_legacy_env_types } from '../env.js'; +import { create_explicit_env_types } from '../env.js'; import { write_if_changed } from './utils.js'; import { posixify } from '../../utils/os.js'; @@ -23,17 +23,13 @@ export function write_env(kit, entry, env_config) { content.push( `// This file is generated from ${relative}.\n${DOCS}`, create_explicit_env_types(env_config, relative, 'private'), - create_explicit_env_types(env_config, relative, 'public'), - create_legacy_env_types(env_config, relative, 'private'), - create_legacy_env_types(env_config, relative, 'public') + create_explicit_env_types(env_config, relative, 'public') ); } else { content.push( DOCS, create_explicit_env_types({}, '', 'private'), - create_explicit_env_types({}, '', 'public'), - create_legacy_env_types({}, '', 'private'), - create_legacy_env_types({}, '', 'public') + create_explicit_env_types({}, '', 'public') ); } diff --git a/packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js index 441c55a76bf0..336ff9408ba0 100644 --- a/packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js +++ b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.server.js @@ -1,4 +1,6 @@ +// @ts-expect-error no type definitions since deprecated import { PRIVATE_STATIC } from '$env/static/private'; +// @ts-expect-error no type definitions since deprecated import { env as dynamic_private } from '$env/dynamic/private'; export function load() { diff --git a/packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte index 0c3fc4146873..730af04c99eb 100644 --- a/packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/env/legacy/+page.svelte @@ -1,5 +1,7 @@