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

@mbrughelli/nestjs-typed-config

v1.1.2

Published

Type-safe configuration module for NestJS applications with Zod validation

Downloads

57

Readme

@mbrughelli/nestjs-typed-config

npm version License: MIT

| Statements | Branches | Functions | Lines | | --------------------------- | ----------------------- | ------------------------- | ----------------- | | Statements | Branches | Functions | Lines |

Type-safe configuration module for NestJS applications with Zod validation. Say goodbye to process.env scattered throughout your codebase and hello to fully typed, validated configuration!

✨ Features

  • 🎯 Type-safe configuration - Full TypeScript support with IntelliSense
  • 🛡️ Runtime validation - Powered by Zod schemas
  • 🧪 Testing utilities - Built-in mocks and test helpers
  • 🚀 Zero configuration - Works out of the box with sensible defaults
  • 🔒 Environment-aware - Built-in development/production/test detection
  • 📝 Self-documenting - Configuration properties with descriptions
  • 🎪 Factory patterns - Easy integration with async module configuration
  • 🌍 Global by default - Available throughout your application

📦 Installation

npm install @mbrughelli/nestjs-typed-config zod
# or
yarn add @mbrughelli/nestjs-typed-config zod
# or
pnpm add @mbrughelli/nestjs-typed-config zod

🚀 Quick Start

1. Define your environment schema

// src/config/env.validation.ts
import { z } from 'zod';

export const envSchema = z.object({
  NODE_ENV: z.enum(['dev', 'production', 'test']).default('dev'),
  PORT: z.coerce.number().default(3000),
  DATABASE_URL: z.string().url(),
  JWT_SECRET: z.string().min(32),
  REDIS_HOST: z.string().default('localhost'),
  REDIS_PORT: z.coerce.number().default(6379),
});

export type Environment = z.infer<typeof envSchema>;

2. Create your typed config service

// src/config/config.service.ts
import { Injectable } from '@nestjs/common';
import { BaseTypedConfigService } from '@mbrughelli/nestjs-typed-config';
import { envSchema, Environment } from './env.validation';

@Injectable()
export class AppConfigService extends BaseTypedConfigService<typeof envSchema> {
  protected readonly schema = envSchema;

  get nodeEnv(): Environment['NODE_ENV'] {
    return this.get('NODE_ENV');
  }

  get port(): Environment['PORT'] {
    return this.get('PORT');
  }

  get databaseUrl(): Environment['DATABASE_URL'] {
    return this.get('DATABASE_URL');
  }

  get jwtSecret(): Environment['JWT_SECRET'] {
    return this.get('JWT_SECRET');
  }

  // Utility methods
  get isDevelopment(): boolean {
    return this.nodeEnv === 'dev';
  }

  get databaseConfig() {
    return {
      url: this.databaseUrl,
      ssl: this.isProduction(),
    };
  }
}

3. Create your config module

// src/config/config.module.ts
import { createTypedConfigModule } from '@mbrughelli/nestjs-typed-config';
import { AppConfigService } from './config.service';
import { envSchema } from './env.validation';

export const ConfigModule = createTypedConfigModule({
  schema: envSchema,
  serviceClass: AppConfigService,
});

4. Import in your app module

// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from './config/config.module';
import { AppConfigService } from './config/config.service';

@Module({
  imports: [ConfigModule],
  // ConfigModule is global, so AppConfigService is available everywhere
})
export class AppModule {}

5. Use anywhere in your application

// src/auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { AppConfigService } from '../config/config.service';

@Injectable()
export class AuthService {
  constructor(private readonly config: AppConfigService) {}

  createToken() {
    // Fully typed! No more process.env.JWT_SECRET
    return jwt.sign(payload, this.config.jwtSecret);
  }
}

🎭 Advanced Usage

Factory Pattern for Async Configuration

// src/database/database.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppConfigService } from '../config/config.service';

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      useFactory: (config: AppConfigService) => ({
        type: 'postgres',
        url: config.databaseUrl,
        ssl: config.isProduction(),
        // ... other options
      }),
      inject: [AppConfigService],
    }),
  ],
})
export class DatabaseModule {}

Environment-Specific Validation

export const createConfigModule = (environment: string) => {
  return createTypedConfigModule({
    schema: envSchema,
    serviceClass: AppConfigService,
    customValidation: environment === 'production' ? (config) => {
      const result = envSchema.parse(config);
      
      // Additional production validations
      if (!result.SENTRY_DSN) {
        throw new Error('SENTRY_DSN is required in production');
      }
      
      return result;
    } : undefined,
  });
};

Testing with Mocks

// src/auth/auth.service.spec.ts
import { Test } from '@nestjs/testing';
import { createTypedConfigMock } from '@mbrughelli/nestjs-typed-config/testing';
import { AppConfigService } from '../config/config.service';
import { envSchema } from '../config/env.validation';
import { AuthService } from './auth.service';

describe('AuthService', () => {
  let service: AuthService;
  
  beforeEach(async () => {
    const mockConfig = createTypedConfigMock(envSchema, {
      JWT_SECRET: 'test-secret-32-characters-long!!!',
      NODE_ENV: 'test',
    });

    const module = await Test.createTestingModule({
      providers: [
        AuthService,
        {
          provide: AppConfigService,
          useValue: mockConfig,
        },
      ],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  // Your tests here...
});

📖 API Reference

BaseTypedConfigService<T>

Abstract base class for your configuration service.

Protected Methods

  • get<K>(key: K): T[K] - Get a configuration value with full type safety
  • getWithFallback<K>(key: K, fallback: T[K]): T[K] - Get a value with fallback
  • getAll(): T - Get all configuration values
  • isTest(): boolean - Check if running in test environment
  • isDevelopment(): boolean - Check if running in development
  • isProduction(): boolean - Check if running in production

createTypedConfigModule(options)

Factory function to create a typed configuration module.

Options

interface TypedConfigOptions<T extends z.ZodSchema> {
  schema: T;                           // Zod schema for validation
  serviceClass: Type<any>;            // Your config service class
  validate?: boolean;                 // Enable validation (default: true)
  ignoreValidationInTest?: boolean;   // Skip validation in test (default: true)
  customValidation?: (config) => T;   // Custom validation function
  isGlobal?: boolean;                 // Make module global (default: true)
}

@ConfigProperty(options?)

Decorator for documenting configuration properties.

@ConfigProperty({ 
  description: 'JWT secret key', 
  required: true, 
  sensitive: true 
})
get jwtSecret() {
  return this.get('JWT_SECRET');
}

🧪 Testing Utilities

The package includes comprehensive testing utilities:

import { 
  createTypedConfigMock, 
  MockTypedConfigService,
  createTestConfig 
} from '@mbrughelli/nestjs-typed-config/testing';

// Create a mock with default values
const mockConfig = createTypedConfigMock(envSchema);

// Create a mock with overrides
const mockConfig = createTypedConfigMock(envSchema, {
  NODE_ENV: 'test',
  PORT: 3001,
});

// Create basic test configuration
const testConfig = createTestConfig();

🔄 Migration Guide

From process.env scattered usage

Before:

// ❌ Scattered throughout your codebase
const jwtSecret = process.env.JWT_SECRET;
const port = parseInt(process.env.PORT || '3000');
const dbUrl = process.env.DATABASE_URL;

After:

// ✅ Centralized, typed, and validated
constructor(private readonly config: AppConfigService) {}

// Fully typed with IntelliSense!
const jwtSecret = this.config.jwtSecret;
const port = this.config.port;
const dbUrl = this.config.databaseUrl;

From NestJS ConfigService

Before:

// ❌ No type safety
constructor(private readonly config: ConfigService) {}

const jwtSecret = this.config.get<string>('JWT_SECRET');
const port = this.config.get<number>('PORT', 3000);

After:

// ✅ Fully typed and validated
constructor(private readonly config: AppConfigService) {}

const jwtSecret = this.config.jwtSecret; // string
const port = this.config.port; // number

🎯 Best Practices

1. Group Related Configuration

export class AppConfigService extends BaseTypedConfigService<typeof envSchema> {
  // Group related configs into objects
  get databaseConfig() {
    return {
      url: this.databaseUrl,
      ssl: this.isProduction(),
      maxConnections: this.databaseMaxConnections,
    };
  }

  get redisConfig() {
    return {
      host: this.redisHost,
      port: this.redisPort,
      password: this.redisPassword,
    };
  }
}

2. Use Computed Properties

export class AppConfigService extends BaseTypedConfigService<typeof envSchema> {
  get maxFileSizeBytes(): number {
    return this.maxFileSizeMb * 1024 * 1024;
  }

  get isSwaggerEnabled(): boolean {
    return this.enableSwagger && !this.isProduction();
  }

  get corsOrigins(): string[] {
    return this.allowedOrigins.split(',').map(origin => origin.trim());
  }
}

3. Environment-Specific Behavior

get logLevel(): LogLevel {
  if (this.isTest()) return 'error';
  if (this.isDevelopment()) return 'debug';
  return this.get('LOG_LEVEL');
}

get shouldEnableSwagger(): boolean {
  return this.isDevelopment() || this.get('ENABLE_SWAGGER');
}

🔧 Template Files

The package includes template files in the templates/ directory:

  • env.validation.example.ts - Comprehensive environment schema
  • config.service.example.ts - Feature-rich configuration service
  • config.module.example.ts - Various module configuration patterns

Copy these files to your project and modify them according to your needs.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • Built on top of NestJS and Zod
  • Inspired by the need for type-safe configuration in NestJS applications
  • Thanks to the open-source community for making this possible

Made with ❤️ for the NestJS community