Skip to main content
Version: 4.0.0-preview

Env validator

Heads up: the legacy Env provider with checkFile() / checkAll() from earlier docs has been replaced in v4 by the unified Configuration system. This page exists to point you to the new pattern; it no longer documents the old provider.

The v4 way to validate environment variables is the combination of:

  1. loadEnvSync() in src/main.ts to load .env files into process.env.
  2. defineConfig + Env.* builders in src/config/app.config.ts to declare every variable, its type, default, and validation rules.

If anything is missing or misshapen, configuration resolution fails fast at startup with a structured error.

Quick example

src/config/app.config.ts
import { defineConfig, Env } from "@expressots/core";

export const appConfig = defineConfig({
app: {
name: Env.string("APP_NAME", { default: "expressots-app" }),
port: Env.port("PORT", { default: 3000 }),
env: Env.enum(
"NODE_ENV",
["development", "production", "test"] as const,
{ default: "development" },
),
},

database: {
url: Env.url("DATABASE_URL", { required: true }),
poolSize: Env.number("DB_POOL_SIZE", { default: 10, min: 1, max: 100 }),
},

auth: {
jwtSecret: Env.secret("JWT_SECRET", { required: true, minLength: 32 }),
},

features: {
flags: Env.array("FEATURE_FLAGS", { default: [], delimiter: "," }),
externalApi: Env.url("EXTERNAL_API_URL", { required: false }),
},
});

export type AppConfig = typeof appConfig;
src/main.ts
import { bootstrap, loadEnvSync } from "@expressots/core";
import { App } from "./app";

loadEnvSync(); // Load .env, .env.${NODE_ENV}, .local overrides
void bootstrap(App); // Validates every Env.* declaration before listen()

If JWT_SECRET is shorter than 32 chars, or DATABASE_URL is unset, or PORT is non-numeric, the boot fails with a single error block listing every issue at once.

Mapping from the legacy provider

Legacy v2/v3v4 equivalent
this.provider.register(Env)(not needed; configuration is always available)
Env.checkFile()loadEnvSync() in main.ts
Env.checkAll()Automatic during defineConfig resolution
Env.get("FOO")appConfig.values.foo (typed)
Manual fallbacksEnv.string("FOO", { default: "bar" })
Manual existence checksEnv.string("FOO", { required: true })
Custom regexEnv.string("FOO", { pattern: /…/ })
Secret redaction in logsEnv.secret("FOO") (auto-redacts in logs and toObject())

See also