Typed, validated client and runtime server environment variables for Vite.
The package is framework-neutral. It validates public values at build time and private values where the server runs, while exposing both through typed virtual modules.
1.0.0-next.0is a prerelease. The API may change before1.0.0.
pnpm add -D vite-env-schema@next// vite.config.ts
import { defineConfig } from "vite";
import envSchema from "vite-env-schema";
export default defineConfig({
plugins: [envSchema()],
});Add an env.ts at the Vite root:
import { defineEnv } from "vite-env-schema/define";
import { z } from "zod";
export default defineEnv({
server: {
DATABASE_URL: z.url(),
SESSION_SECRET: z.string().min(32),
},
client: {
VITE_API_URL: z.url(),
VITE_APP_NAME: z.string().min(1),
},
});Any Standard Schema validator works, including Zod, Valibot and ArkType.
Client values are validated and embedded during the build:
import { env } from "virtual:env/client";
console.log(env.VITE_API_URL);Server values are read and validated at runtime:
import { env, getEnv } from "virtual:env/server";
console.log(env.DATABASE_URL);
export function handleRequest() {
const current = getEnv();
return current.SESSION_SECRET;
}virtual:env/server cannot be imported from a client module graph. Client keys must use Vite's public envPrefix, and server keys must not use it.
Node uses process.env by default. A deployment integration can provide another source:
// vite.config.ts
envSchema({
server: {
source: "./env.runtime.ts",
},
});// env.runtime.ts
import type { RuntimeEnvironmentSource } from "vite-env-schema/define";
const source: RuntimeEnvironmentSource = () => process.env;
export default source;The source may export an environment object or a synchronous function returning one. getEnv() caches validation by source-object identity, which supports request-scoped sources that return a different object for each request.
| Client | Server | |
|---|---|---|
| Source | Vite .env and build environment |
process.env or configured runtime source |
| Validation | Build time | Runtime |
| Output | Frozen object embedded in the client build | Runtime-validated object |
| Virtual module | virtual:env/client |
virtual:env/server |
The plugin also:
- generates
vite-env-schema.d.tsfrom the schema - watches the schema and
.envfiles in development - rejects server-module imports from client graphs
- checks client chunks for known server values
- supports Vite environment consumers rather than hard-coded environment names
Server validators must be synchronous so server output does not require top-level await. Client validators may be asynchronous.
envSchema({
schema: "./config/env.ts",
types: "./src/vite-env-schema.d.ts",
server: {
source: "./src/env.runtime.ts",
},
});Set types: false to disable declaration generation.
The schema convention, virtual module names and leak detection build on @vite-env/core. Runtime server validation and provider-supplied sources come from the requirements encountered while integrating full-stack Solid applications. The package is maintained as framework-neutral Vite infrastructure.
MIT