Skip to main content

Environment variables

Environment variables are values your app needs that exist separately from the app's source code. They allow you to use sensitive information like API keys and database credentials without storing them in version control.

During development, and at build time, variables defined in a .env or .env.local file will be added to the environment:

.env
API_KEY=19f401ba-e8b0-48c4-8c77-b0ebb26d97fe

After following the setup below, they can be imported via the following modules:

Legacy mode

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

Add a src/env.ts (or src/env.js) file that exports a variables object:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
export const const variables: DefinedEnvVars<{}>variables = defineEnvVars<{}>(variables: {}): DefinedEnvVars<{}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
// ... });

Each value in the object passed to defineEnvVars is an EnvVarConfig object that configures the environment variable.

defineEnvVars returns its argument unaltered — it exists purely to help with type safety.

Private variables

By default, all variables are considered private. For example, you don't want to reveal your API_KEY:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
export const
const variables: DefinedEnvVars<{
    API_KEY: {};
}>
variables
=
defineEnvVars<{
    API_KEY: {};
}>(variables: {
    API_KEY: {};
}): DefinedEnvVars<{
    API_KEY: {};
}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
type API_KEY: {}API_KEY: {} });

Since no configuration is needed for this variable, we can use an empty object ({}).

Now that API_KEY is defined, it can be imported into app code via $app/env/private:

import { import API_KEYAPI_KEY } from '$app/env/private';

The $app/env/private module cannot be imported into code that runs in the browser, so that you can't accidentally reveal your secrets in a JavaScript bundle.

Public variables

Some variables are perfectly safe — necessary, even — to expose to the browser. For these, we can specify public: true:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
export const
const variables: DefinedEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
    };
}>
variables
=
defineEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
    };
}>(variables: {
    GOOGLE_ANALYTICS_ID: {
        public: true;
    };
}): DefinedEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
    };
}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
type GOOGLE_ANALYTICS_ID: {
    public: true;
}
GOOGLE_ANALYTICS_ID
: {
public: truepublic: true } });

GOOGLE_ANALYTICS_ID can now be imported from $app/env/public, or used in your app.html template as %sveltekit.env.GOOGLE_ANALYTICS_ID%:

src/app
<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		%sveltekit.head%

		<script
			async
			src="https://www.googletagmanager.com/gtag/js?id=%sveltekit.env.GOOGLE_ANALYTICS_ID%"
		></script>

		<script>
			window.dataLayer ??= [];
			function gtag(){dataLayer.push(arguments)}
			gtag('js', new Date());
			gtag('config', '%sveltekit.env.GOOGLE_ANALYTICS_ID%');
		</script>
	</head>
	<body data-sveltekit-preload-data="hover">
		<div style="display: contents">%sveltekit.body%</div>
	</body>
</html>

Validation

You can specify a Standard Schema validator such as Zod or Valibot to check that an environment variable value is correct:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
import * as import vv from 'valibot'; export const
const variables: DefinedEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
    };
}>
variables
=
defineEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
    };
}>(variables: {
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
    };
}): DefinedEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
    };
}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
type GOOGLE_ANALYTICS_ID: {
    public: true;
    schema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
}
GOOGLE_ANALYTICS_ID
: {
public: truepublic: true, schema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>schema: import vv.
pipe<v.StringSchema<undefined>, v.RegexAction<string, undefined>>(schema: v.StringSchema<undefined>, item1: v.RegexAction<string, undefined> | v.PipeAction<string, string, v.RegexIssue<string>>): v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]> (+20 overloads)
export pipe

Adds a pipeline to a schema, that can validate and transform its input.

@param
schema The root schema.
@param
item1 The first pipe item.
@returns
A schema with a pipeline.
pipe
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returns
A string schema.
string
(), import vv.
regex<string>(requirement: RegExp): v.RegexAction<string, undefined> (+1 overload)
export regex

Creates a regex validation action.

Hint: Be careful with the global flag g in your regex pattern, as it can lead to unexpected results. See MDN for more information.

@param
requirement The regex pattern.
@returns
A regex action.
regex
(/G-[A-Z0-9]+/))
} });

If you don't want to bring in a schema library, you can pass a function that returns the (possibly transformed) value, or throws an error explaining the problem:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
export const
const variables: DefinedEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: (value: string | undefined) => string;
    };
}>
variables
=
defineEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: (value: string | undefined) => string;
    };
}>(variables: {
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: (value: string | undefined) => string;
    };
}): DefinedEnvVars<{
    GOOGLE_ANALYTICS_ID: {
        public: true;
        schema: (value: string | undefined) => string;
    };
}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
type GOOGLE_ANALYTICS_ID: {
    public: true;
    schema: (value: string | undefined) => string;
}
GOOGLE_ANALYTICS_ID
: {
public: truepublic: true, schema: (value: string | undefined) => stringschema: (value: string | undefinedvalue) => { if (!value: string | undefinedvalue?.String.startsWith(searchString: string, position?: number): boolean

Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.

startsWith
('G-')) throw new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('expected a Google Analytics ID');
return value: stringvalue; } } });

If a value is invalid, the app will fail to start (or build). To opt out of one or the other, use building from $app/env along with a validator that accepts an optional value:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
import { const building: boolean

SvelteKit analyses your app during the build step by running it. During this process, building is true. This also applies during prerendering.

building
} from '$app/env'
import * as import vv from 'valibot'; export const
const variables: DefinedEnvVars<{
    SECRET: {
        schema: v.StringSchema<undefined> | v.OptionalSchema<v.StringSchema<undefined>, undefined>;
    };
}>
variables
=
defineEnvVars<{
    SECRET: {
        schema: v.StringSchema<undefined> | v.OptionalSchema<v.StringSchema<undefined>, undefined>;
    };
}>(variables: {
    SECRET: {
        schema: v.StringSchema<undefined> | v.OptionalSchema<v.StringSchema<undefined>, undefined>;
    };
}): DefinedEnvVars<{
    SECRET: {
        schema: v.StringSchema<undefined> | v.OptionalSchema<v.StringSchema<undefined>, undefined>;
    };
}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
type SECRET: {
    schema: v.StringSchema<undefined> | v.OptionalSchema<v.StringSchema<undefined>, undefined>;
}
SECRET
: {
// optional when building but required when starting the app schema: v.StringSchema<undefined> | v.OptionalSchema<v.StringSchema<undefined>, undefined>schema: const building: boolean

SvelteKit analyses your app during the build step by running it. During this process, building is true. This also applies during prerendering.

building
? import vv.
optional<v.StringSchema<undefined>>(wrapped: v.StringSchema<undefined>): v.OptionalSchema<v.StringSchema<undefined>, undefined> (+1 overload)
export optional

Creates an optional schema.

@param
wrapped The wrapped schema.
@returns
An optional schema.
optional
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returns
A string schema.
string
()) : import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returns
A string schema.
string
()
} });

You can use validators to make values optional, or transform them (such as turning a string into a boolean, or parsing JSON) — see your validation library's documentation to learn how.

Static variables

By default, variables are dynamic. If a variable is configured with static: true, it will be inlined into your application code, enabling optimisations like dead-code elimination:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
import * as import vv from 'valibot'; export const
const variables: DefinedEnvVars<{
    SHOW_DEBUG_OVERLAY: {
        public: true;
        static: true;
        schema: v.SchemaWithPipe<readonly [v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>]>;
    };
}>
variables
=
defineEnvVars<{
    SHOW_DEBUG_OVERLAY: {
        public: true;
        static: true;
        schema: v.SchemaWithPipe<readonly [v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>]>;
    };
}>(variables: {
    SHOW_DEBUG_OVERLAY: {
        public: true;
        static: true;
        schema: v.SchemaWithPipe<readonly [v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>]>;
    };
}): DefinedEnvVars<{
    SHOW_DEBUG_OVERLAY: {
        public: true;
        static: true;
        schema: v.SchemaWithPipe<readonly [v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>]>;
    };
}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
type SHOW_DEBUG_OVERLAY: {
    public: true;
    static: true;
    schema: v.SchemaWithPipe<readonly [v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>]>;
}
SHOW_DEBUG_OVERLAY
: {
public: truepublic: true, static: truestatic: true, // coerce to true/false schema: v.SchemaWithPipe<readonly [v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>]>schema: import vv.
pipe<v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>>(schema: v.OptionalSchema<v.StringSchema<undefined>, "">, item1: v.TransformAction<string, boolean> | v.PipeAction<string, boolean, never>): v.SchemaWithPipe<readonly [v.OptionalSchema<v.StringSchema<undefined>, "">, v.TransformAction<string, boolean>]> (+20 overloads)
export pipe

Adds a pipeline to a schema, that can validate and transform its input.

@param
schema The root schema.
@param
item1 The first pipe item.
@returns
A schema with a pipeline.
pipe
(
import vv.
optional<v.StringSchema<undefined>, "">(wrapped: v.StringSchema<undefined>, default_: ""): v.OptionalSchema<v.StringSchema<undefined>, ""> (+1 overload)
export optional

Creates an optional schema.

@param
wrapped The wrapped schema.
@param
default_ The default value.
@returns
An optional schema.
optional
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returns
A string schema.
string
(), ''),
import vv.
transform<string, boolean>(operation: (input: string) => boolean): v.TransformAction<string, boolean>
export transform

Creates a custom transformation action.

@param
operation The transformation operation.
@returns
A transform action.
transform
((str: stringstr) => str: stringstr !== '')
) } });

Because this variable is static, the <DebugOverlay> component shown here will be excluded from the JavaScript bundle unless SHOW_DEBUG_OVERLAY is truthy:

<script>
	import { SHOW_DEBUG_OVERLAY } from '$app/env/public';
	import DebugOverlay from '#lib/components/DebugOverlay.svelte';
</script>

{#if SHOW_DEBUG_OVERLAY}
	<DebugOverlay />
{/if}

But if the variable is set before building the app...

SHOW_DEBUG_OVERLAY=true npm run build

...then the component will be included and shown.

Documenting variables

You can document the purpose of an environment variable by adding a description:

src/env
import { function defineEnvVars<T extends Record<string, EnvVarConfig<any>>>(variables: T): DefinedEnvVars<T>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
} from '@sveltejs/kit/env';
export const
const variables: DefinedEnvVars<{
    CACHE_TTL_SECONDS: {
        description: string;
    };
}>
variables
=
defineEnvVars<{
    CACHE_TTL_SECONDS: {
        description: string;
    };
}>(variables: {
    CACHE_TTL_SECONDS: {
        description: string;
    };
}): DefinedEnvVars<{
    CACHE_TTL_SECONDS: {
        description: string;
    };
}>

Utility for defining environment variables, which are made available via $app/env/public and $app/env/private.

@example
import { defineEnvVars } from '@sveltejs/kit/env';
import * as v from 'valibot';

export const variables = defineEnvVars({
	API_URL: {
		schema: v.pipe(v.string(), v.url())
	},
	PORT: {
		schema: (value) => {
			if (value === undefined) return 3000;
			const port = Number(value);
			if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
			return port;
		}
	}
});
defineEnvVars
({
type CACHE_TTL_SECONDS: {
    description: string;
}
CACHE_TTL_SECONDS
: {
description: stringdescription: 'How long to cache responses, in seconds' } });

Hovering over CACHE_TTL_SECONDS in your app code will show the description.

Edit this page on GitHub llms.txt