Use with NestJS

Validate and type environment variables in NestJS with a fail-fast env module.

Edit on GitHub

ArkEnv validates and types your environment variables when the module is imported. In a NestJS application, validating environment variables at module evaluation time gives you fail-fast runtime safety before the Nest IoC container bootstraps.

Setup

Define and validate your environment variables in src/env.ts. Export the typed env object:

src/env.ts
import  from "@arkenv/core";

export const  = ({
  : "'development' | 'production' | 'test' = 'development'",
  : "number.port = 3000",
  : "string",
});

Import env directly across your controllers, services, and modules:

src/app.service.ts
import { Injectable } from "@nestjs/common";
import { env } from "./env";

@Injectable()
export class AppService {
  getDatabaseUrl(): string {
    return env.DATABASE_URL;
  }
}

Fail-fast entrypoint

Import env at the top of src/main.ts before calling NestFactory.create(). If any required environment variables are missing or invalid, the process terminates immediately before initializing NestJS modules, providers, or database connections.

src/main.ts
import { env } from "./env";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(env.PORT);
}
bootstrap();

Execution

Load your .env file before executing Node.js so that process.env is populated before src/env.ts evaluates. With Node.js 20.6+ and @nestjs/cli 11+, use the native --env-file flag with the Nest CLI:

nest start --env-file .env

On @nestjs/cli 10 and earlier, build the app first and run node --env-file=.env dist/main.js.

For production builds, ensure environment variables are injected by your deployment platform or container runner before the Node process boots.

Optional DI provider

If you prefer dependency injection over module-scoped imports, register env with a Symbol injection token using a custom provider:

src/env.provider.ts
import { env } from "./env";

export const ENV = Symbol("ENV");
export type Env = typeof env;

export const EnvProvider = {
  provide: ENV,
  useValue: env,
};

Register EnvProvider in your module's providers array (and exports if used across modules), then inject ENV into services using @Inject(ENV) private readonly env: Env.

Why avoid ConfigModule validation

Do not pass an ArkEnv schema shape into @nestjs/config's ConfigModule.forRoot({ validationSchema }).

Starting in @nestjs/config 12, validationSchema supports Standard Schema validators, but @nestjs/config passes raw string environment variables directly to the schema without automatic type coercion. A non-coercing validator (like ArkType's number.port or Zod's z.number()) rejects "3000" with a type error instead of parsing it. In @nestjs/config 11 and earlier, validationSchema doesn't support Standard Schema validators.

Using ArkEnv directly in src/env.ts handles string coercion automatically and fails immediately before NestJS initializes.

HTTP validation vs. environment validation

NestJS 12 supports Standard Schema pipes (such as StandardSchemaValidationPipe) for HTTP request payloads (@Body(), @Query()). HTTP validation pipes validate incoming requests at runtime and are distinct from application environment variable validation.