The default Turbo environment variables patterns do not work in SvelteKit v2.0. Turbo has VITE_*
for SvelteKit, but SvelteKit uses PUBLIC_*
as the default prefix for public env vars.
[!TIP] Turbo framework inference should use
PUBLIC_*
as the default prefix for env vars. Framework inference documentation should stress that variables not included in the framework defaults or explicitly inturbo.json
will not be available for the build.
There is no prefix for private env vars. SvelteKit default is that anything not prefixed with PUBLIC_
is private and can be used in routes. However, this means private env vars must be listed explicitly in turbo.json
in the env
array.
[!NOTE] See this PR for an issue demo.
Follow these steps to demonstrate the issue.
npx create-turbo@latest -e with-svelte
@sveltejs/adapter-vercel
and update svelte.config.js
:import adapter from '@sveltejs/adapter-vercel';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
};
export default config;
apps/web/.env
(this file is not in source control):PUBLIC_ENV_VAR="abc123"
SECRET_ENV_VAR="def456"
PUBLIC_ENV_VAR
to apps/web/src/routes/+page.svelte
:<script lang="ts">
import { PUBLIC_ENV_VAR } from '$env/static/public';
import { MyCounterButton } from '@repo/ui';
export let data;
</script>
<h1>Turbo Env Var Repro</h1>
<MyCounterButton />
<p>Environment variables:</p>
<pre>
{JSON.stringify(
{
...data,
PUBLIC_ENV_VAR: `Imported on the client from $env/static/public: ${PUBLIC_ENV_VAR}`
},
null,
2
)}
</pre>
SECRET_ENV_VAR
to apps/web/src/routes/api/index.ts
:import { SECRET_ENV_VAR } from '$env/static/private';
export function load() {
return {
SECRET_ENV_VAR: `Loaded on the server from $env/static/private: ${SECRET_ENV_VAR}`
};
}
Run pnpm dev
in apps/web
. Open in the browser. The env vars are displayed as expected.
Deploy to Vercel. The build will fail with an error similar to:
web:build: error during build:
web:build: RollupError: "PUBLIC_ENV_VAR" is not exported by "virtual:$env/static/public", imported by "src/routes/+page.svelte".
web:build: file: /vercel/path0/apps/web/src/routes/+page.svelte:2:10
web:build: 1: <script lang="ts">
web:build: 2: import { PUBLIC_ENV_VAR } from '$env/static/public';
web:build: ^
web:build: 3: import { env } from '$env/dynamic/public';
web:build: 4: import { MyCounterButton } from '@repo/ui';
Add PUBLIC_ENV_VAR
and SECRET_ENV_VAR
to the Vercel project settings UI. Redeploy the project. The build will fail with the same error.
Update turbo.json
to include PUBLIC_*
and PRIVATE_*
in the env
array:
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT", ".env*"],
"outputs": [".svelte-kit/**", ".vercel/**"],
"env": ["PUBLIC_*", "SECRET_ENV_VAR"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}