vite-plugin-env-schema

raw JSON →
1.0.2 verified Mon Apr 27 auth: no javascript

A Vite plugin (v1.0.2) for build-time validation and injection of environment variables using schema libraries like Zod, Valibot, ArkType, and Effect Schema via the Standard Schema V1 spec. It validates .env values against a defined schema early in the Vite config resolution (or on module load) and exposes them through a virtual module `virtual:env`. Key differentiators from other env plugins (e.g., @julr/vite-plugin-validate-env) include full compatibility with any Standard Schema library and zero runtime dependencies beyond the schema library. Released in July 2025 with an active maintenance cadence.

error Cannot find module 'virtual:env' or its corresponding type declarations.
cause Missing TypeScript declaration file for the virtual module.
fix
Create an env.d.ts file in your project root declaring module 'virtual:env' with the correct type inference.
error Error: Invalid environment variables: - VITE_API_URL: Expected string, received undefined
cause Environment variable not defined in .env file or not prefixed with VITE_ and exposed.
fix
Ensure the variable is present in your .env file and, if using Vite's default env prefix, it starts with VITE_.
error Type 'boolean' is not assignable to type 'never' when using z.boolean().default(false)
cause Schema default value type mismatch due to missing coercion or incorrect schema shape.
fix
Use z.coerce.boolean() for env vars that are strings 'true'/'false' or ensure the default matches the string representation.
breaking Default validateOn changed from 'load' to 'config' between v0.x and v1.0.0.
fix If you relied on 'load' behavior, set validateOn: 'load' explicitly in plugin options.
gotcha The virtual module 'virtual:env' is resolved at build time only; tests or runtime code outside Vite will throw 'Cannot find module'.
fix Use conditional requires or mock the module in test environments (e.g., vitest config with resolve.alias).
gotcha Schema must be an object with string-to-string record fields (env vars are always strings initially). Non-string default values (e.g., numbers) require coercion (e.g., z.coerce.number()).
fix Use z.coerce for number/boolean defaults, or validate transformed values after string parsing.
deprecated The package switched from deepmerge to @standard-schema/spec in v1.0.1; any custom validation logic relying on deepmerge is now unsupported.
fix Update to latest version; custom validation should implement Standard Schema V1.
npm install vite-plugin-env-schema
yarn add vite-plugin-env-schema
pnpm add vite-plugin-env-schema

Basic validation with Zod: creates env schema, injects validated vars, demonstrates TypeScript declaration for type-safe access.

// vite.config.ts
import { defineConfig } from 'vite'
import envPlugin from 'vite-plugin-env-schema'
import { z } from 'zod'

const envSchema = z.object({
  VITE_API_URL: z.string().url(),
  VITE_DEBUG: z.boolean().default(false),
  VITE_PORT: z.coerce.number().int().positive().default(3000),
})

export default defineConfig({
  plugins: [envPlugin(envSchema, { validateOn: 'config' })],
})

// env.d.ts (for TypeScript clients)
declare module 'virtual:env' {
  import type { z } from 'zod'
  import type envSchema from './vite.config'
  const env: z.infer<typeof envSchema>
  export default env
}

// src/main.ts
import env from 'virtual:env'
console.log(env.VITE_API_URL) // https://example.com
console.log(env.VITE_DEBUG)    // false (default)