no-raw-env
Disallow direct process.env and import.meta.env reads outside validated boundaries.
Why
Raw environment reads are untyped and defer invalid configuration failures until use. One shared validated settings object gives consumers a consistent startup configuration.
Fix
Define a Zod settings schema, call SettingsSchema.parse(process.env) once at startup, and export or inject that single parsed settings object. Use Pydantic/Pydantic Settings for the equivalent Python boundary. Required values must fail before remote effects; preserve independent security policy and existing optional defaults.
Examples
import { z } from "zod";const SettingsSchema = z.object({ API_KEY: z.string().min(1) });export const settings = SettingsSchema.parseAsync(process.env);import { z } from "zod";const SettingsSchema = z.object({ API_KEY: z.string().min(1) });export const settings = await SettingsSchema.parseAsync(process.env);const createEnv = (input) => input;export const settings = createEnv(process.env);import { z } from "zod";const SettingsSchema = z.object({ API_KEY: z.string().min(1) });const createEnv = (input) => input;export const settings = SettingsSchema.parse(createEnv(process.env));export const settings = JSON.parse(process.env.SETTINGS_JSON);import { z } from "zod";const SettingsSchema = z.object({ API_ORIGIN: z.url() });export const settings = SettingsSchema.parse(JSON.parse(process.env.SETTINGS_JSON));import { env as raw } from "node:process";export const databaseUrl = raw.DATABASE_URL;import { settings } from "./env.js";export const databaseUrl = settings.DATABASE_URL;import { env as raw } from "node:process";import { z } from "zod";const SettingsSchema = z.object({ DATABASE_URL: z.url() });export const settings = SettingsSchema.parse(raw);import { z } from "zod";const SettingsSchema = z.object({ DATABASE_URL: z.url() });export const settings = { DATABASE_URL: process.env.DATABASE_URL };import { settings } from "./env.js";export const primaryUrl = settings.DATABASE_URL;export const replicaUrl = settings.DATABASE_URL;import { z } from "zod";const SettingsSchema = z.object({ DATABASE_URL: z.url() });export const settings = SettingsSchema.parse(process.env);import { z } from "zod";const SettingsSchema = z.object({ API_ORIGIN: z.url() });export const settings = SettingsSchema.parse( process.env.LOAD_REMOTE ? fetch("https://example.test/config") : {},);import { z } from "zod";const SettingsSchema = z.object({ LOAD_REMOTE: z.enum(["0", "1"]).transform((value) => value === "1"),});export const settings = SettingsSchema.parse(process.env);if (settings.LOAD_REMOTE) await fetch("https://example.test/config");import { env as raw } from "node:process";import { z } from "zod";const SettingsSchema = z.object({ API_KEY: z.string().min(1) });const { API_KEY, API_ORIGIN } = raw;export const settings = SettingsSchema.parse({ API_KEY });export const unparsedOrigin = API_ORIGIN;import { env as raw } from "node:process";import { z } from "zod";const SettingsSchema = z.object({ API_KEY: z.string().min(1), API_ORIGIN: z.url() });const { API_KEY, API_ORIGIN } = raw;export const settings = SettingsSchema.parse({ API_KEY, API_ORIGIN });