
Security News
RubyGems Adds Cooldown Feature to Bundler for Newly Published Gems
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.
@hazeljs/config
Advanced tools
Config that validates itself. No more process.env.UNDEFINED at runtime.
Schema-based, type-safe, validated on startup. .env files, nested config, transforms. Fail fast if something's missing — before users hit your API.
npm install @hazeljs/config
import { IsString, IsNumber, IsEnum } from 'class-validator';
export enum Environment {
Development = 'development',
Production = 'production',
Test = 'test',
}
export class AppConfig {
@IsEnum(Environment)
NODE_ENV: Environment;
@IsNumber()
PORT: number;
@IsString()
DATABASE_URL: string;
@IsString()
JWT_SECRET: string;
@IsString()
REDIS_URL: string;
}
import { HazelModule } from '@hazeljs/core';
import { ConfigModule } from '@hazeljs/config';
import { AppConfig } from './app.config';
@HazelModule({
imports: [
ConfigModule.forRoot({
schema: AppConfig,
envFilePath: '.env',
validate: true,
}),
],
})
export class AppModule {}
import { Injectable } from '@hazeljs/core';
import { ConfigService } from '@hazeljs/config';
@Injectable()
export class DatabaseService {
constructor(private configService: ConfigService<AppConfig>) {}
connect() {
const dbUrl = this.configService.get('DATABASE_URL');
const port = this.configService.get('PORT');
console.log(`Connecting to database: ${dbUrl}`);
console.log(`Server will run on port: ${port}`);
}
}
ConfigModule.forRoot({
schema: AppConfig,
envFilePath: [
'.env',
`.env.${process.env.NODE_ENV}`,
'.env.local',
],
validate: true,
})
Files are loaded in order, with later files overriding earlier ones:
.env - Base configuration.env.${NODE_ENV} - Environment-specific.env.local - Local overrides (gitignored)NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT_SECRET=your-super-secret-key
REDIS_URL=redis://localhost:6379
# API Keys
OPENAI_API_KEY=sk-...
STRIPE_API_KEY=sk_test_...
# Feature Flags
ENABLE_ANALYTICS=true
ENABLE_CACHING=true
import { IsString, IsNumber, IsUrl, IsBoolean } from 'class-validator';
export class AppConfig {
@IsString()
NODE_ENV: string;
@IsNumber()
PORT: number;
@IsUrl()
DATABASE_URL: string;
@IsString()
JWT_SECRET: string;
@IsBoolean()
ENABLE_CACHING: boolean;
}
import { IsString, ValidateIf, MinLength } from 'class-validator';
export class AppConfig {
@IsString()
@MinLength(32, { message: 'JWT_SECRET must be at least 32 characters' })
JWT_SECRET: string;
@ValidateIf(o => o.NODE_ENV === 'production')
@IsString()
SSL_CERT_PATH: string;
}
import { Transform } from 'class-transformer';
export class AppConfig {
@Transform(({ value }) => parseInt(value, 10))
@IsNumber()
PORT: number;
@Transform(({ value }) => value === 'true')
@IsBoolean()
ENABLE_CACHING: boolean;
@Transform(({ value }) => value.split(','))
ALLOWED_ORIGINS: string[];
}
export class DatabaseConfig {
@IsString()
host: string;
@IsNumber()
port: number;
@IsString()
username: string;
@IsString()
password: string;
@IsString()
database: string;
}
export class AppConfig {
@IsString()
NODE_ENV: string;
@ValidateNested()
@Type(() => DatabaseConfig)
database: DatabaseConfig;
}
import { Injectable } from '@hazeljs/core';
import { ConfigService } from '@hazeljs/config';
@Injectable()
export class MyService {
constructor(private config: ConfigService<AppConfig>) {}
doSomething() {
const apiKey = this.config.get('OPENAI_API_KEY');
const port = this.config.get('PORT');
}
}
import { InjectConfig } from '@hazeljs/config';
@Injectable()
export class MyService {
constructor(
@InjectConfig('DATABASE_URL') private dbUrl: string,
@InjectConfig('PORT') private port: number
) {}
connect() {
console.log(`Connecting to ${this.dbUrl} on port ${this.port}`);
}
}
Organize configuration into logical groups:
export class DatabaseConfig {
@IsString()
url: string;
@IsNumber()
poolSize: number;
}
export class RedisConfig {
@IsString()
url: string;
@IsNumber()
ttl: number;
}
export class AppConfig {
@ValidateNested()
@Type(() => DatabaseConfig)
database: DatabaseConfig;
@ValidateNested()
@Type(() => RedisConfig)
redis: RedisConfig;
}
// Usage
const dbConfig = this.config.get('database');
console.log(dbConfig.url);
console.log(dbConfig.poolSize);
export class AppConfig {
@IsNumber()
@Default(3000)
PORT: number;
@IsBoolean()
@Default(false)
ENABLE_DEBUG: boolean;
@IsString()
@Default('info')
LOG_LEVEL: string;
}
Load configuration from external sources:
ConfigModule.forRoot({
schema: AppConfig,
load: [
async () => {
// Load from database
const settings = await database.settings.findMany();
return settings.reduce((acc, s) => ({
...acc,
[s.key]: s.value,
}), {});
},
async () => {
// Load from API
const response = await fetch('https://api.example.com/config');
return await response.json();
},
],
})
class ConfigService<T = any> {
// Get configuration value
get<K extends keyof T>(key: K): T[K];
get<K extends keyof T>(key: K, defaultValue: T[K]): T[K];
// Get all configuration
getAll(): T;
// Check if key exists
has(key: keyof T): boolean;
// Get with type casting
getOrThrow<K extends keyof T>(key: K): T[K];
}
# .gitignore
.env
.env.local
.env.*.local
.env # Base configuration
.env.development # Development overrides
.env.production # Production overrides
.env.test # Test overrides
.env.local # Local overrides (gitignored)
ConfigModule.forRoot({
schema: AppConfig,
validate: true,
validationOptions: {
allowUnknown: false,
abortEarly: false,
},
})
// Good - Type-safe
const port = this.config.get('PORT'); // number
// Bad - Not type-safe
const port = process.env.PORT; // string | undefined
/**
* Application Configuration
*
* Required Environment Variables:
* - NODE_ENV: Application environment (development|production|test)
* - PORT: Server port number
* - DATABASE_URL: PostgreSQL connection string
* - JWT_SECRET: Secret key for JWT tokens (min 32 characters)
* - REDIS_URL: Redis connection string
*/
export class AppConfig {
// ...
}
// config/app.config.ts
import { IsString, IsNumber, IsEnum, IsUrl } from 'class-validator';
import { Transform } from 'class-transformer';
export enum Environment {
Development = 'development',
Production = 'production',
Test = 'test',
}
export class AppConfig {
@IsEnum(Environment)
NODE_ENV: Environment;
@Transform(({ value }) => parseInt(value, 10))
@IsNumber()
PORT: number;
@IsUrl()
DATABASE_URL: string;
@IsString()
JWT_SECRET: string;
@IsUrl()
REDIS_URL: string;
@IsString()
OPENAI_API_KEY: string;
@Transform(({ value }) => value === 'true')
ENABLE_CACHING: boolean;
}
// app.module.ts
@HazelModule({
imports: [
ConfigModule.forRoot({
schema: AppConfig,
envFilePath: ['.env', `.env.${process.env.NODE_ENV}`],
validate: true,
}),
],
})
export class AppModule {}
// database.service.ts
@Injectable()
export class DatabaseService {
constructor(private config: ConfigService<AppConfig>) {}
async connect() {
const url = this.config.get('DATABASE_URL');
// Connect to database
}
}
npm test
Contributions are welcome! Please read our Contributing Guide for details.
Apache 2.0 © HazelJS
FAQs
Configuration module for HazelJS framework
The npm package @hazeljs/config receives a total of 347 weekly downloads. As such, @hazeljs/config popularity was classified as not popular.
We found that @hazeljs/config demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.

Security News
Federal audit finds NIST lacked a plan to clear the NVD backlog, wasted funds on duplicate work, and delayed use of CISA data.