Skip to main content

NestJS integration

Env Core integrates seamlessly with NestJS’s ConfigModule. This guide shows you how to validate environment variables during your NestJS application’s initialization.

Basic setup

Here’s how to integrate Env Core with NestJS:
1

Define your environment schema

Create a schema file for your environment variables:
src/envSchema.ts
import type { EnvSchema } from 'env-core';

export const envSchema = {
  PORT: Number,
  NODE_ENV: String,
  DEBUG: {
    type: Boolean,
    default: false,
  },
  HOST: {
    type: String,
    default: '0.0.0.0',
    required: false,
  },
} satisfies EnvSchema;
2

Configure ConfigModule with validation

Use Env Core’s validateEnv function as the validation function in ConfigModule:
src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { validateEnv } from 'env-core';
import { envSchema } from './envSchema';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validate: (config) => validateEnv(envSchema, config),
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
NestJS passes the configuration object to the validate function. Env Core validates it and returns the typed environment object.
3

Create your .env file

Add your environment variables to a .env file in your project root:
.env
PORT=3000
NODE_ENV=development
DEBUG=true

Validation behavior

If the validation fails, NestJS will not initialize, and a descriptive error message will be thrown:
Error: Environment validation failed:
- Missing required field: NODE_ENV
- Missing required field: DEBUG
- PORT should be a number
When using Env Core with NestJS, validation errors are thrown as exceptions rather than calling process.exit(). This allows NestJS’s error handling to work properly.

Using validated environment in services

Once configured, you can inject the ConfigService to access your validated environment variables:
src/app.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import type { ValidatedEnv } from 'env-core';
import type { envSchema } from './envSchema';

type Env = ValidatedEnv<typeof envSchema>;

@Injectable()
export class AppService {
  constructor(private configService: ConfigService<Env>) {}

  getServerInfo() {
    const port = this.configService.get('PORT', { infer: true });
    const env = this.configService.get('NODE_ENV', { infer: true });
    const debug = this.configService.get('DEBUG', { infer: true });

    return {
      port,
      environment: env,
      debug,
    };
  }
}
Use the ValidatedEnv type with your schema to get full type safety when using ConfigService.

Complete example

Here’s a complete NestJS application with Env Core:
src/envSchema.ts
import type { EnvSchema } from 'env-core';

export const envSchema = {
  PORT: Number,
  NODE_ENV: String,
  DATABASE_URL: String,
  DEBUG: { type: Boolean, default: false },
  REDIS_HOST: { type: String, default: 'localhost' },
  REDIS_PORT: { type: Number, default: 6379 },
} satisfies EnvSchema;
src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { validateEnv } from 'env-core';
import { envSchema } from './envSchema';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validate: (config) => validateEnv(envSchema, config),
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return 'Hello World!';
  }

  @Get('info')
  getInfo() {
    return this.appService.getServerInfo();
  }
}
src/main.ts
import { NestFactory } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';
import { AppModule } from './app.module';
import type { ValidatedEnv } from 'env-core';
import type { envSchema } from './envSchema';

type Env = ValidatedEnv<typeof envSchema>;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  const configService = app.get(ConfigService<Env>);
  const port = configService.get('PORT', { infer: true });
  
  await app.listen(port);
  console.log(`Application is running on: http://localhost:${port}`);
}

bootstrap();

Common NestJS environment variables

Here are typical environment variables for a NestJS application:
export const envSchema = {
  // Server
  PORT: Number,
  NODE_ENV: String,
  
  // Database
  DATABASE_URL: String,
  DATABASE_NAME: String,
  DB_POOL_SIZE: { type: Number, default: 10 },
  
  // Redis
  REDIS_HOST: { type: String, default: 'localhost' },
  REDIS_PORT: { type: Number, default: 6379 },
  REDIS_PASSWORD: { type: String, required: false },
  
  // JWT
  JWT_SECRET: String,
  JWT_EXPIRATION: { type: String, default: '1h' },
  
  // Features
  DEBUG: { type: Boolean, default: false },
  ENABLE_SWAGGER: { type: Boolean, default: true },
  
  // External APIs
  API_KEY: String,
  API_URL: String,
} satisfies EnvSchema;

Using environment in modules

You can use the validated environment when configuring other modules:
src/database.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import type { ValidatedEnv } from 'env-core';
import type { envSchema } from './envSchema';

type Env = ValidatedEnv<typeof envSchema>;

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService<Env>) => ({
        type: 'postgres',
        url: configService.get('DATABASE_URL', { infer: true }),
        autoLoadEntities: true,
        synchronize: configService.get('NODE_ENV', { infer: true }) === 'development',
      }),
      inject: [ConfigService],
    }),
  ],
})
export class DatabaseModule {}

Type-safe configuration service

Create a wrapper around ConfigService for better type safety:
src/config/env.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import type { ValidatedEnv } from 'env-core';
import type { envSchema } from '../envSchema';

type Env = ValidatedEnv<typeof envSchema>;

@Injectable()
export class EnvService {
  constructor(private configService: ConfigService<Env>) {}

  get<K extends keyof Env>(key: K): Env[K] {
    return this.configService.get(key, { infer: true })!;
  }

  isDevelopment(): boolean {
    return this.get('NODE_ENV') === 'development';
  }

  isProduction(): boolean {
    return this.get('NODE_ENV') === 'production';
  }
}
Register it as a provider:
@Module({
  providers: [EnvService],
  exports: [EnvService],
})
export class ConfigModule {}
Use it in your services:
@Injectable()
export class AppService {
  constructor(private env: EnvService) {}

  getInfo() {
    return {
      port: this.env.get('PORT'),
      debug: this.env.get('DEBUG'),
      isDev: this.env.isDevelopment(),
    };
  }
}

Best practices

Set isGlobal: true so you don’t need to import ConfigModule in every module:
ConfigModule.forRoot({
  isGlobal: true,
  validate: (config) => validateEnv(envSchema, config),
})
Export a type alias for your validated environment to use throughout your app:
export type Env = ValidatedEnv<typeof envSchema>;
Wrap ConfigService in a custom service for better type safety and utility methods:
@Injectable()
export class EnvService {
  constructor(private config: ConfigService<Env>) {}
  
  get<K extends keyof Env>(key: K): Env[K] {
    return this.config.get(key, { infer: true })!;
  }
}
ConfigModule validates environment variables during module initialization, ensuring configuration is correct before any services start.

Next steps

Express.js integration

See how to use Env Core with Express.js

Type safety

Learn more about TypeScript type inference

Build docs developers (and LLMs) love