A lightweight utility to check the presence and validity of environment variables, as specified by a Zod schema
npm install validate-env-vars


 \



A lightweight utility for checking the presence and validity of environment variables, as specified by a Zod schema.
validate-env-vars supports Zod v4 and Zod Mini!
Using npm:
``bash`
npm install validate-env-vars --save-dev
`javascript
#!/usr/bin/env node
import validateEnvVars from 'validate-env-vars';
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
API_BASE: z.url(),
GITHUB_USERNAME: z.string().min(1),
});
validateEnvVars({ schema: envSchema });
`
---
`javascript
import validateEnvVars from 'validate-env-vars';
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
API_BASE: z.url(),
GITHUB_USERNAME: z.string().min(1),
});
const preflight = () => {
try {
validateEnvVars({ schema: envSchema, envPath: '.env.production' });
// ... other code
} catch (error) {
console.error(error);
// ... other code
}
};
`
---
1. Define a Zod schema in a .ts file at the root of your project
`javascript
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
VITE_API_BASE: z.url(),
VITE_GITHUB_USERNAME: z.string().min(1),
});
// make the type of the environment variables available globally
declare global {
type Env = z.infer
}
export default envSchema;
`
2. Import validateEnvVars and your schema and add a plugin to your Vite config to call validateEnvVars on buildStart
`javascript
import { defineConfig } from 'vitest/config';
import envConfigSchema from './env.config';
import validateEnvVars from 'validate-env-vars';
export default defineConfig({
plugins: [
{
name: 'validate-env-vars',
buildStart: () => validateEnvVars({ schema: envConfigSchema }),
},
// other plugins...
],
// other options...
`
3. Enable typehints and intellisense for the environment variables in your vite-env.d.ts
`javascript
///
interface ImportMetaEnv extends globalThis.Env {}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
`
4. Add your schema configuration file to your tsconfig's include
| Option | Type | Description | Default |
| ------------------------ | ----------- | -------------------------------------------------------------- | ------- |
| schema | EnvObject | The schema to validate against (must use string-based types) | |envPath
| (optional) | string | The path to the .env file | |exitOnError
| (optional) | boolean | Whether to exit the process or throw if validation fails | false |logVars
| (optional) | boolean | Whether to output successfully parsed variables to the console | true |
Note: The schema must be a z.object() whose fields use string-based types—such as z.string(), z.enum(), z.literal(), or compositions like union/optional of these types. You may also use any Zod string refinements and formats (e.g., .min(), .max(), .url(), .email(), .regex(), .refine(), etc.) to validate and transform string values. Environment variables are always read as strings.
Since environment variables are always read as strings, you'll need to validate and transform them appropriately. Here are some common patterns:
`javascript
const envNonEmptyString = () =>
z
.string()
.min(1, { message: 'Variable cannot be empty' })
.refine((val) => val !== 'undefined', {
message: "Variable cannot equal 'undefined'",
});
// Integer from string
const envInteger = () =>
z.string().regex(/^-?\d+$/, {
message: 'Variable must be a valid integer',
});
// Boolean from string
const envBoolean = () => z.enum(['true', 'false']);
// Comma-separated list
const envList = () =>
z.string().transform((val) => val.split(',').map((s) => s.trim()));
``