npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@buka/nestjs-config

v2.4.3

Published

An easy to use nestjs config module

Downloads

43,743

Readme

@buka/nestjs-config

version downloads dependencies license Codecov

An easy-to-use NestJS config module with powerful features and type safety.

Features

  • Type-Safe Configuration: Config verification by class-validator
  • Config Transformation: Config transform by class-transformer
  • Flexible Loading: Load configuration from multiple sources (env, files, etc.)
  • Hot Reload: Automatically reload configuration when files change (opt-in)
  • Auto Naming Convention: Automatically handles naming styles (camelCase, snake_case, etc.)
  • Injectable Classes: Configuration classes can be injected like any other provider
  • Global Configuration: Define configuration once, use everywhere
  • Perfect Type Hints: Full TypeScript support with excellent IDE autocomplete

Installation

npm install @buka/nestjs-config
# or
yarn add @buka/nestjs-config
# or
pnpm add @buka/nestjs-config

Quick Start

1. Create Configuration Class

Define your configuration using decorators from class-validator:

// app.config.ts
import { Configuration } from "@buka/nestjs-config";
import { IsString, IsOptional, IsIn, IsIp } from "class-validator";
import { Split } from "@miaooo/class-transformer-split";

@Configuration()
export class AppConfig {
  @IsIp()
  host = "0.0.0.0"; // default value

  @IsString()
  @IsOptional()
  cacheDir?: string;

  @IsIn(["dev", "test", "prod"])
  nodeEnv: string;

  @Split(",")
  brokers: string[];
}

2. Create Environment File

Create a .env file in your project root:

# .env
CACHE_DIR="./tmp"
NODE_ENV="dev"
BROKERS="test01.test.com,test02.test.com,test03.test.com"

[!TIP] @buka/nestjs-config automatically converts naming styles. cache_dir, CACHE_DIR, cacheDir, CacheDir, cache-dir, Cache_Dir are all recognized as the same config name.

3. Import ConfigModule

Import ConfigModule in your NestJS application:

// app.module.ts
import { Module } from "@nestjs/common";
import { ConfigModule } from "@buka/nestjs-config";

@Module({
  imports: [ConfigModule.register({ isGlobal: true })],
})
export class AppModule {}

By default, ConfigModule loads config from process.env and .env file.

4. Inject Configuration

Use configuration in your services:

// app.service.ts
import { Injectable } from "@nestjs/common";
import { AppConfig } from "./app.config";

@Injectable()
export class AppService {
  constructor(private readonly appConfig: AppConfig) {}

  getInfo() {
    return `Host: ${this.appConfig.host}, Env: ${this.appConfig.nodeEnv}`;
  }
}

Configuration

Global Configuration (Recommended)

When you need to use configuration in multiple places (NestJS modules, ORM configs, scripts), use ConfigModule.configure() to avoid duplication:

Step 1: Create Configuration File

// config/index.ts
import {
  ConfigModule,
  processEnvLoader,
  yamlFileLoader,
} from "@buka/nestjs-config";

ConfigModule.configure({
  loaders: [processEnvLoader(), yamlFileLoader("config.yaml")],
  suppressWarnings: true,
});

Step 2: Use in NestJS Module

// app.module.ts
import { Module } from "@nestjs/common";
import { ConfigModule } from "@buka/nestjs-config";
import "./config"; // Import configuration

@Module({
  imports: [
    ConfigModule.register({ isGlobal: true }), // Uses global config
  ],
})
export class AppModule {}

Step 3: Use in External Files (ORM configs, scripts, etc.)

// mikro-orm.config.ts
import { ConfigModule } from "@buka/nestjs-config";
import { DatabaseConfig } from "./config/database.config";
import "./config"; // Import configuration

export default (async function () {
  await ConfigModule.preload(); // Uses global config
  const config = await ConfigModule.getOrFail(DatabaseConfig);
  return { ...config };
})();

[!TIP] Benefits of Global Configuration:

  • Configure once, use everywhere
  • No duplication between preload() and register()
  • Guaranteed consistency across your application
  • Can still override settings when needed by passing options directly

Configuration Options

interface ConfigModuleOptions {
  /**
   * Configuration loaders (default: processEnvLoader + .env file)
   */
  loaders?: (string | ConfigLoader)[];

  /**
   * Suppress warning messages
   */
  suppressWarnings?: boolean;

  /**
   * Enable debug logging
   */
  debug?: boolean;

  /**
   * Manually specify config providers (usually auto-detected)
   */
  providers?: Type[];
}

Custom Loaders

You can customize how configuration is loaded:

import {
  ConfigModule,
  processEnvLoader,
  dotenvLoader,
} from "@buka/nestjs-config";

ConfigModule.configure({
  loaders: [
    processEnvLoader(),
    dotenvLoader(".env", { separator: "__", jsonParse: true }),
    dotenvLoader(`.env.${process.env.NODE_ENV}`),
  ],
});

Advanced Usage

Nested Configuration

import { Configuration } from "@buka/nestjs-config";
import { ValidateNested, Type } from "class-transformer";
import { IsString } from "class-validator";

export class DatabaseConfig {
  @IsString()
  host: string; // DATABASE__HOST

  @IsString()
  password: string; // DATABASE__PASSWORD
}

@Configuration()
export class AppConfig {
  @ValidateNested()
  @Type(() => DatabaseConfig)
  database: DatabaseConfig;
}

Environment variables: DATABASE__HOST=localhost, DATABASE__PASSWORD=secret

Configuration Prefix

Use @Configuration(prefix) to add a prefix to all properties:

import { Configuration } from "@buka/nestjs-config";
import { IsString } from "class-validator";

@Configuration("mysql.master")
export class MysqlConfig {
  @IsString()
  host: string; // MYSQL__MASTER__HOST
}

Mapping:

  • process.env: MYSQL__MASTER__HOST
  • .env file: MYSQL__MASTER__HOST
  • JSON file: { mysql: { master: { host: "..." } } }

Custom Config Keys

Use @ConfigKey() to override the property name:

import { Configuration, ConfigKey } from "@buka/nestjs-config";
import { IsString } from "class-validator";

@Configuration("mysql")
export class MysqlConfig {
  @ConfigKey("DATABASE_HOST")
  @IsString()
  host: string; // Now reads from DATABASE_HOST instead of MYSQL__HOST
}

[!NOTE] @ConfigKey(name) overwrites the prefix from @Configuration(prefix)

Preload Config (Outside NestJS)

Use ConfigModule.preload() to load configuration before NestJS initialization:

// database-migration.ts
import { ConfigModule } from "@buka/nestjs-config";
import { DatabaseConfig } from "./config/database.config";
import "./config"; // Import global configuration

async function migrate() {
  await ConfigModule.preload(); // Uses global config

  // Get configuration
  const config = await ConfigModule.getOrFail(DatabaseConfig);

  // Use config for migration...
}

Module Integration

Simplify configuration injection into other modules using ConfigModule.inject():

import { Module } from "@nestjs/common";
import { ConfigModule, Configuration } from "@buka/nestjs-config";
import { LoggerModule } from "nestjs-pino";
import { IsIn } from "class-validator";

@Configuration("logger")
class LoggerConfig {
  @IsIn(["fatal", "error", "warn", "info", "debug", "trace"])
  level: string = "info";
}

@Module({
  imports: [
    ConfigModule.register({ isGlobal: true }),

    // Using ConfigModule.inject() - Simple and clean
    ConfigModule.inject(LoggerConfig, LoggerModule, (config) => ({
      pinoHttp: { level: config.level },
    })),
  ],
})
class AppModule {}

Configuration Hot Reload

The module supports hot-reloading of configuration files, allowing your application to automatically pick up configuration changes without restarting.

Basic Usage

Enable hot reload per loader using the hotReload option:

import {
  ConfigModule,
  dotenvLoader,
  jsonFileLoader,
  yamlFileLoader,
} from "@buka/nestjs-config";

@Module({
  imports: [
    ConfigModule.register({
      isGlobal: true,
      loaders: [
        // Enable hot reload with default settings (file watcher)
        dotenvLoader(".env", { hotReload: true }),

        // Enable hot reload for JSON file
        jsonFileLoader("./config.json", "utf-8", { hotReload: true }),

        // Enable hot reload for YAML file
        yamlFileLoader("./config.yaml", "utf-8", { hotReload: true }),
      ],
    }),
  ],
})
export class AppModule {}

Advanced Usage - Watch Types and Hooks

You can customize the watch behavior for each loader:

ConfigModule.register({
  loaders: [
    // File system watch (default, recommended)
    dotenvLoader(".env", {
      hotReload: {
        type: "watch", // Use chokidar file system watcher
        debounceMs: 500, // Wait 500ms before reloading (default: 300ms)

        onChange: async (newConfig) => {
          console.log("Config file changed, new config:", newConfig);
        },

        onError: async (error) => {
          console.error("Failed to reload config:", error);
        },
      },
    }),

    // Polling mode (for network drives or special filesystems)
    jsonFileLoader("./config.json", "utf-8", {
      hotReload: {
        type: "interval", // Use polling instead of file watching
        intervalMs: 5000, // Check every 5 seconds (default: 5000ms)
        debounceMs: 300,
      },
    }),
  ],
});

Manual Reload

You can also manually trigger configuration reload:

import { ConfigModule } from "@buka/nestjs-config";

// In your service or controller
async reloadConfig() {
  try {
    await ConfigModule.reload();
    return { message: "Configuration reloaded successfully" };
  } catch (error) {
    throw new Error(`Failed to reload config: ${error.message}`);
  }
}

This is useful when:

  • Configuration is updated programmatically (not via file changes)
  • You need to reload configuration on demand (e.g., admin endpoint)
  • Testing configuration changes

How It Works

  • Each loader can independently enable hot reload with its own settings
  • When a file changes, the loader triggers a global configuration reload
  • All configuration provider instances are updated in-place
  • Injected configuration objects automatically reflect the new values
  • If validation fails, the old configuration is preserved (rollback)

Notes

  • Hot reload is configured per loader (opt-in for each file)
  • Supports both watch mode (file system events) and interval mode (polling)
  • Environment variable loader (processEnvLoader) does not support watching
  • Each loader has independent debouncing (default: 300ms)
  • Configuration validation still applies on reload
  • Manual reload via ConfigModule.reload() is also available

Equivalent without ConfigModule.inject():

@Module({
  imports: [
    ConfigModule.register({ isGlobal: true }),

    // Using forRootAsync directly - More verbose
    LoggerModule.forRootAsync({
      inject: [LoggerConfig],
      useFactory: (config: LoggerConfig) => ({
        pinoHttp: { level: config.level },
      }),
    }),
  ],
})
class AppModule {}

As you can see, ConfigModule.inject() provides a cleaner syntax for injecting configuration into other modules.

Advanced: Inject with additional options

import { TypeOrmModule } from "@nestjs/typeorm";

@Configuration("database")
class DatabaseConfig {
  @IsString()
  host: string;

  @IsNumber()
  port: number;

  @IsString()
  database: string;
}

@Module({
  imports: [
    ConfigModule.register({ isGlobal: true }),

    // With additional module options (e.g., multiple databases)
    ConfigModule.inject(
      DatabaseConfig,
      TypeOrmModule,
      { name: "primary" }, // Additional options
      (config) => config, // Config mapper (optional)
    ),
  ],
})
class AppModule {}

Equivalent to:

TypeOrmModule.forRootAsync({
  name: "primary",
  inject: [DatabaseConfig],
  useFactory: (config: DatabaseConfig) => config,
});

Built-in Loaders

| Loader | Description | | --------------------------------- | ----------------------------------------------------------------------------------------- | | processEnvLoader() | Load from process.env | | dotenvLoader(path, options?) | Load .env file using dotenv | | dotenvxLoader(path, options?) | Load .env file using @dotenvx/dotenvx | | jsonFileLoader(path) | Load JSON file | | yamlFileLoader(path, encoding?) | Load YAML file using yaml | | tomlFileLoader(path, encoding?) | Load TOML file using smol-toml |

Custom Loader Example

import { ConfigLoader, ConfigModuleOptions } from "@buka/nestjs-config";
import { readFileSync } from "fs";

export function customLoader(filepath: string): ConfigLoader {
  return (options: ConfigModuleOptions) => {
    const content = readFileSync(filepath, "utf-8");
    // Parse and return configuration object
    return JSON.parse(content);
  };
}

Troubleshooting

Error: "Every field in my Config class was missing"

This may occur when using TypeScript with target set to ES2021 or lower.

Solution 1 (Recommended): Upgrade to ES2022 or higher in tsconfig.json

Solution 2: Add @ConfigKey() decorator to every property:

import { Configuration, ConfigKey } from "@buka/nestjs-config";

@Configuration()
export class AppConfig {
  @ConfigKey()
  @IsIp()
  host = "0.0.0.0";

  @ConfigKey()
  @IsIn(["dev", "test", "prod"])
  nodeEnv: string;
}

Error: "Nest could not find YourConfig element"

This occurs when a config class is not injected into any service.

Solution 1: Use ConfigModule.get() instead of app.get():

await ConfigModule.preload();
const config = await ConfigModule.get(YourConfig);

Solution 2: Manually register the config class:

@Module({
  imports: [
    ConfigModule.register({
      isGlobal: true,
      providers: [YourConfig],
    }),
  ],
})
class AppModule {}

License

MIT