createEnv
The main function to create a type-safe environment configuration.
Signature
function createEnv<
TPrefix extends string | undefined,
TServer extends StandardSchemaDictionary,
TClient extends StandardSchemaDictionary,
TShared extends StandardSchemaDictionary,
TExtends extends Record<string, unknown>[],
TPlugins extends NevrEnvPlugin[]
>(options: EnvOptions): CreateEnvResultOptions
server
Server-side environment variables. These are validated on the server and protected from client access.
createEnv({
server: {
DATABASE_URL: z.string().url(),
API_SECRET: z.string().min(32),
},
runtimeEnv: process.env,
});client
Client-side environment variables. Must use the clientPrefix.
createEnv({
client: {
NEXT_PUBLIC_API_URL: z.string().url(),
NEXT_PUBLIC_APP_NAME: z.string(),
},
clientPrefix: "NEXT_PUBLIC_",
runtimeEnv: process.env,
});shared
Variables available on both server and client.
createEnv({
shared: {
NODE_ENV: z.enum(["development", "production", "test"]),
},
runtimeEnv: process.env,
});clientPrefix
Required prefix for client-side variables. Helps prevent accidental server variable exposure.
createEnv({
clientPrefix: "NEXT_PUBLIC_", // Next.js
// or
clientPrefix: "VITE_", // Vite
// or
clientPrefix: "EXPO_PUBLIC_", // Expo
});runtimeEnv
Source of environment variables. Usually process.env.
createEnv({
runtimeEnv: process.env,
});runtimeEnvStrict
Explicit list of runtime variables. More strict than runtimeEnv.
createEnv({
server: {
API_KEY: z.string(),
},
runtimeEnvStrict: {
API_KEY: process.env.API_KEY,
},
});experimental__runtimeEnv
For Next.js 13.4.4+. Only client variables need explicit destructuring.
createEnv({
server: {
DATABASE_URL: z.string().url(), // Auto from process.env
},
client: {
NEXT_PUBLIC_URL: z.string().url(),
},
experimental__runtimeEnv: {
NEXT_PUBLIC_URL: process.env.NEXT_PUBLIC_URL,
},
});plugins
Array of nevr-env plugins.
import { createEnv, postgres, stripe } from "nevr-env";
createEnv({
plugins: [
postgres(),
stripe({ webhook: true }),
],
runtimeEnv: process.env,
});extends
Extend from other env configurations.
import { baseEnv } from "./base-env";
createEnv({
extends: [baseEnv],
server: {
EXTRA_VAR: z.string(),
},
runtimeEnv: process.env,
});emptyStringAsUndefined
Treat empty strings as undefined. Default: false.
createEnv({
emptyStringAsUndefined: true,
// Now: PORT="" is treated as PORT=undefined
});skipValidation
Skip validation (for build time). Default: false.
createEnv({
skipValidation: process.env.SKIP_ENV_VALIDATION === "true",
});isServer
Override server detection.
createEnv({
isServer: typeof window === "undefined",
});onValidationError
Custom error handler for validation failures.
createEnv({
onValidationError: (issues) => {
console.error("ENV VALIDATION FAILED:");
issues.forEach((issue) => {
console.error(` ${issue.path}: ${issue.message}`);
});
process.exit(1);
},
});onInvalidAccess
Custom error handler for invalid client access to server variables.
createEnv({
onInvalidAccess: (varName) => {
throw new Error(`Cannot access ${varName} on client`);
},
});validationMode
Control how validation errors are handled. Default: "strict".
"strict"— throws on validation error (default)"warn"— logs warnings and continues with potentially invalid env
createEnv({
server: { ... },
validationMode: "warn", // Log warnings instead of throwing
runtimeEnv: process.env,
});WARNING
Never use "warn" mode in production for security-critical variables.
debug
Enable verbose logging for troubleshooting. Default: false.
createEnv({
server: { ... },
debug: true,
runtimeEnv: process.env,
});
// Logs: schema keys, available env keys, server detection resultonSuccess
Callback invoked after successful validation. Useful for logging, telemetry, or initializing services.
createEnv({
server: { ... },
onSuccess: (env) => {
console.log("Environment validated with", Object.keys(env).length, "keys");
},
runtimeEnv: process.env,
});createFinalSchema
Custom schema combination for cross-field validation.
createEnv({
server: {
DB_HOST: z.string(),
DB_PORT: z.coerce.number(),
},
createFinalSchema: (shape, isServer) => {
return z.object(shape).refine(
(data) => data.DB_HOST || data.DATABASE_URL,
{ message: "Either DB_HOST or DATABASE_URL required" }
);
},
});Return Value
Returns a Readonly proxy object with all validated environment variables.
const env = createEnv({ ... });
// Access variables
env.DATABASE_URL; // string
env.NODE_ENV; // "development" | "production" | "test"
// Type error for non-existent
env.TYPO; // ❌ TypeScript error
// Runtime error on client for server vars
env.API_SECRET; // ❌ Throws on clientExamples
Basic Next.js
import { createEnv } from "nevr-env";
import { z } from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
NODE_ENV: z.enum(["development", "production", "test"]),
},
client: {
NEXT_PUBLIC_APP_URL: z.string().url(),
},
clientPrefix: "NEXT_PUBLIC_",
runtimeEnv: process.env,
});With Plugins
import { createEnv } from "nevr-env";
import { postgres, stripe } from "nevr-env";
import { z } from "zod";
export const env = createEnv({
plugins: [
postgres({ directUrl: true }),
stripe({ webhook: true }),
],
server: {
NODE_ENV: z.enum(["development", "production", "test"]),
},
client: {
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string(),
},
clientPrefix: "NEXT_PUBLIC_",
runtimeEnv: process.env,
});Vite
import { createEnv } from "nevr-env";
import { z } from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
},
client: {
VITE_API_URL: z.string().url(),
},
clientPrefix: "VITE_",
runtimeEnv: import.meta.env,
});