validate-env-vars
v2.1.0
Published
A lightweight utility to check the presence and validity of environment variables, as specified by a Zod schema
Downloads
1,251
Maintainers
Readme
Installation
Requires Node.js 20.12.0 or later and Zod v4. The package has no install-time scripts and supports npm, pnpm, Yarn, and Bun.
Using npm:
npm install --save-dev validate-env-vars zodUsing pnpm:
pnpm add --save-dev validate-env-vars zodUsing Yarn:
yarn add --dev validate-env-vars zodUsing Bun:
bun add --dev validate-env-vars zodUsage Examples
Create an executable JS file to check an .env file against a Zod schema:
#!/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, envPath: '.env' });Programmatically check an .env.production file against a Zod schema:
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
}
};Check env vars before Vite startup and build
- Define a Zod schema in a .ts file at the root of your project
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<typeof envSchema>;
}
export default envSchema;- Import
validateEnvVarsand your schema and add a plugin to your Vite config to callvalidateEnvVarsonbuildStart
import { defineConfig } from 'vite';
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...
});- Enable typehints and intellisense for the environment variables in your
vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv extends globalThis.Env {}
interface ImportMeta {
readonly env: ImportMetaEnv;
}- Add your schema configuration file to your tsconfig's
include
Config Options
| Option | Type | Description | Default |
| ------------------------ | ----------- | ---------------------------------------------------------------------------------------- | ------- |
| schema | EnvObject | The schema to validate against (must use string-based types) | |
| envPath (optional) | string | The path to load with Node's process.loadEnvFile() before validation | |
| exitOnError (optional) | boolean | Whether to exit the process or throw if validation fails | false |
| logVars (optional) | boolean | Whether to output successfully parsed values. Do not enable this where logs are retained | false |
envPath loads variables into process.env, as Node's process.loadEnvFile() does. Call the validator during application bootstrap if you use this option.
Security: logVars defaults to false, so successful values are not printed. Leave it disabled for secrets, CI logs, shared terminals, and production. Set logVars: true only when it is safe to expose the values.
Schema support: schema must be a z.object() whose fields use string-based types, such as z.string(), z.enum(), z.literal(), or unions and optionals composed from those types. String refinements and formats such as .min(), .max(), .url(), .email(), .regex(), and .refine() are supported. Pipelines, transforms, preprocessors, and non-string types are rejected. Environment variables are always read as strings.
Schema Recipes
Since environment variables are always read as strings, you'll need to validate them appropriately. Here are some common patterns:
const envNonEmptyString = () =>
z
.string()
.min(1, { message: 'Variable cannot be empty' })
.refine((val) => val !== 'undefined', {
message: "Variable cannot equal 'undefined'",
});
// Integer from string (with stringFormat)
const envInteger = () =>
z.stringFormat('int', (val) => z.int().safeParse(Number(val)).success);
// Integer from string (with refine)
const envIntegerRefine = () =>
z.string().refine((val) => Number.isInteger(Number(val)), {
message: 'Variable must be an integer',
});
// Boolean from string
const envBoolean = () => z.enum(['true', 'false']);