Examples
Advanced Patterns
Custom transformations, complex validation, and more
Advanced Patterns
Custom Transformations
Transform environment variables during validation.
import { defineEnv, z } from "nviron";
const env = defineEnv({
// Split comma-separated list
ALLOWED_ORIGINS: z
.string()
.transform((val) => val.split(","))
.refine((origins) => origins.length > 0, {
message: "At least one origin is required",
}),
// Parse JSON
FEATURE_FLAGS: z
.string()
.transform((val) => JSON.parse(val))
.pipe(z.record(z.boolean())),
// Convert to uppercase
ENVIRONMENT: z.string().transform((val) => val.toUpperCase()),
// Parse range
ALLOWED_PORTS: z
.string()
.transform((val) => val.split("-").map(Number))
.refine((ports) => ports.length === 2 && ports[0] < ports[1], {
message: "Invalid port range",
}),
});
// Usage:
console.log(env.ALLOWED_ORIGINS); // ['http://localhost:3000', 'https://app.com']
console.log(env.FEATURE_FLAGS); // { analytics: true, beta: false }
console.log(env.ENVIRONMENT); // 'PRODUCTION'
console.log(env.ALLOWED_PORTS); // [3000, 4000]Complex Validation
Advanced validation patterns with custom rules.
import { defineEnv, z } from "nviron";
const env = defineEnv({
// URL with specific requirements
DATABASE_URL: z
.string()
.url()
.refine((url) => url.startsWith("postgresql://"), {
message: "Database must be PostgreSQL",
})
.refine(
(url) =>
!url.includes("localhost") || process.env.NODE_ENV === "development",
{
message: "Localhost database not allowed in production",
},
),
// Conditional validation
SMTP_HOST: z.string().refine(
(host) => {
const nodeEnv = process.env.NODE_ENV;
if (nodeEnv === "production") {
return host.length > 0;
}
return true;
},
{
message: "SMTP_HOST is required in production",
},
),
// Cross-field validation
MIN_POOL_SIZE: z.coerce.number().int(),
MAX_POOL_SIZE: z.coerce.number().int(),
}).refine((data) => data.MIN_POOL_SIZE < data.MAX_POOL_SIZE, {
message: "MIN_POOL_SIZE must be less than MAX_POOL_SIZE",
path: ["MAX_POOL_SIZE"],
});Environment-Specific Schemas
Different schemas for different environments.
import { defineEnv, z } from "nviron";
const baseSchema = {
NODE_ENV: z.enum(["development", "production", "test"]),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
};
const developmentSchema = {
...baseSchema,
DEBUG: z.coerce.boolean().default(true),
MOCK_APIS: z.coerce.boolean().default(true),
};
const productionSchema = {
...baseSchema,
SENTRY_DSN: z.string().url(),
NEW_RELIC_KEY: z.string(),
CDN_URL: z.string().url(),
};
const isProduction = process.env.NODE_ENV === "production";
export const env = defineEnv(
isProduction ? productionSchema : developmentSchema,
);For more examples, check out the Best Practices guide.