@nextnode/config-manager
v3.1.5
Published
A TypeScript configuration management library with automatic type generation from JSON config files. Provides environment-aware configuration loading with intelligent type inference.
Maintainers
Readme
@nextnode/config-manager
A powerful TypeScript configuration management library with automatic type generation from your JSON config files. Provides flexible, environment-aware configuration loading with intelligent type inference, eliminating the need for manual type annotations.
✨ Key Features
🚀 Automatic Type Generation
- Zero configuration: Types are automatically generated from your JSON config files
- Smart detection: Automatically detects user projects and config directories
- Intelligent caching: Only regenerates types when config files change
- Perfect type safety: Eliminates optional chaining (
?.) in your configuration access
🎯 Enhanced Type Inference
- No generics needed:
getConfig()automatically infers precise types - Path-based inference:
getConfig('email.from')returns the exact type - Module augmentation: Optional schema declaration for even more precise types
💪 Robust & Maintainable
- Modern error handling: Meaningful error propagation without silent failures
- Clean architecture: Refactored codebase following modern TypeScript patterns
- Zero defensive coding: Eliminates unnecessary try-catch blocks and fallbacks
Core Features
- 🚀 Automatic type generation - Generates precise TypeScript types from your JSON config files
- 🎯 Intelligent type inference - No generics needed, automatic type detection from config structure
- 🔧 Environment-based configuration - Support for multiple environments (development, staging, production)
- 🛡️ Perfect type safety - Eliminates optional chaining with precise generated types
- 📁 Smart config detection - Automatically finds config directories (config/, configs/, src/config/, etc.)
- 🎯 Dot notation access - Easy access to nested configuration values with type safety
- 🔄 Intelligent caching - Hash-based change detection, only regenerates when needed
- ✅ Configuration validation - Built-in validation for required configuration paths
- 🌍 Environment detection - Automatic environment detection with manual override
- 💪 Robust error handling - Modern error patterns with meaningful error propagation
- 📦 Zero configuration - Works out of the box for most project structures
Installation
npm install @nextnode/config-managerOr with pnpm:
pnpm add @nextnode/config-managerOr with yarn:
yarn add @nextnode/config-managerQuick Start
Basic Usage
import { getConfig, initConfig } from '@nextnode/config-manager'
// Initialize the configuration system (automatically detects config/ directory)
initConfig({
configDir: './config', // optional, auto-detected
environment: 'development', // optional, auto-detected from NODE_ENV
cache: true, // optional, defaults to true
})
// Get configuration values with automatic type inference
const appName = getConfig('app.name') // string - no generics needed!
const emailProvider = getConfig('email.provider') // string
const features = getConfig('app.features') // string[]
// Get entire configuration sections with perfect types
const emailConfig = getConfig('email') // EmailConfig with all properties typed
const appConfig = getConfig('app') // AppConfig with all properties typed
const fullConfig = getConfig() // Complete config object, fully typed
// Perfect type safety - no optional chaining needed!
console.log(emailConfig.from) // ✅ Direct access
console.log(appConfig.features.length) // ✅ Array methods availableConfiguration File Structure
Create configuration files in your project's config directory:
config/
├── default.json # Base configuration
├── development.json # Development overrides
├── staging.json # Staging overrides
└── production.json # Production overridesExample config/default.json:
{
"app": {
"name": "My Application",
"version": "1.0.0",
"features": ["authentication", "analytics"],
"environment": "development"
},
"email": {
"provider": "resend",
"from": "[email protected]",
"to": "[email protected]",
"templates": {
"projectRequest": {
"subject": "New Project Request",
"companyName": "Your Company",
"websiteUrl": "https://example.com"
}
}
}
}Example config/production.json:
{
"app": {
"environment": "production"
},
"email": {
"provider": "nodemailer",
"from": "[email protected]",
"to": "[email protected]"
}
}🚀 Automatic Type Generation
The library automatically generates precise TypeScript types from your JSON configuration files, providing perfect type safety without any manual setup.
How It Works
- Auto-Detection: When you install
@nextnode/config-managerin your project, it automatically detects if you have aconfig/directory - Smart Generation: On first use of
initConfig()orgetConfig(), it scans your JSON files and generates TypeScript definitions - Intelligent Caching: Types are only regenerated when your config files change (using MD5 hash comparison)
- Zero Configuration: Works out of the box with standard project structures
Generated Type Files
The system creates a types/config.d.ts file in your project root:
// types/config.d.ts (auto-generated)
declare module '@nextnode/config-manager' {
interface UserConfigSchema {
app: {
name: string
version: string
features: string[]
environment: string
}
email: {
provider: string
from: string
to: string
templates: {
projectRequest: {
subject: string
companyName: string
websiteUrl: string
}
}
}
}
}Project Detection
The auto-generation system detects user projects by:
- ✅ Finding a
config/directory in your project root - ✅ Checking that the current project is NOT
@nextnode/config-manageritself - ✅ Supporting various config directory names (
config/,configs/,src/config/, etc.)
Manual Type Generation
You can also generate types manually using the CLI:
# Generate types for your config directory
npx @nextnode/config-manager generate-types
# Custom config directory
npx @nextnode/config-manager generate-types ./my-config ./types/my-config.d.tsAPI Reference
Configuration Functions
initConfig(options?)
Initialize the configuration system with custom options. Automatically triggers type generation for user projects.
initConfig({
environment?: string // Override auto-detected environment
configDir?: string // Custom config directory path (auto-detected if not provided)
cache?: boolean // Enable/disable caching (default: true)
})New Behavior:
- Automatically detects
config/directory in your project root - Triggers type generation on first initialization
- Only regenerates types when config files change
getConfig(path?, environment?) / getConfig<T>(path?, environment?)
Get configuration value with automatic type inference. No generics needed in most cases!
// ✨ NEW: Automatic type inference (recommended)
const value = getConfig('email.from') // string
const features = getConfig('app.features') // string[]
const emailConfig = getConfig('email') // EmailConfig
const allConfig = getConfig() // Full config object
// Legacy: Manual type specification (still supported)
const value = getConfig<string>('email.from')
const features = getConfig<string[]>('app.features')
// Environment override
const prodEmail = getConfig('email.from', 'production')Type Inference Features:
- Path-based inference: Return type automatically matches your config structure
- Section inference: Getting
'email'returns the completeEmailConfiginterface - Full config inference: Calling
getConfig()returns the complete typed configuration
hasConfig(path, environment?)
Check if a configuration path exists.
if (hasConfig('email.templates.welcome')) {
// Configuration exists
}validateRequiredConfig(requiredPaths, environment?)
Validate that required configuration paths exist.
const validation = validateRequiredConfig([
'app.name',
'email.from',
'email.provider',
])
if (!validation.valid) {
console.error('Missing required config:', validation.missing)
}Utility Functions
getEnvironment()
Get the current environment name.
const env = getEnvironment() // 'development', 'staging', 'production', etc.getAvailableEnvironments()
Get list of all available configuration environments.
const environments = getAvailableEnvironments()
// ['default', 'development', 'staging', 'production']clearConfigCache()
Clear the configuration cache (useful for testing or hot reloading).
clearConfigCache()Advanced Utilities
deepMerge(target, source)
Deep merge configuration objects.
import { deepMerge } from '@nextnode/config-manager'
const merged = deepMerge(baseConfig, overrideConfig)getNestedValue<T>(object, path)
Get nested value using dot notation.
import { getNestedValue } from '@nextnode/config-manager'
const value = getNestedValue(config, 'email.templates.welcome.subject')setNestedValue(object, path, value)
Set nested value using dot notation.
import { setNestedValue } from '@nextnode/config-manager'
setNestedValue(config, 'email.provider', 'sendgrid')TypeScript Support
🚀 Automatic Type Generation (Recommended)
The library now automatically generates precise TypeScript definitions from your JSON config files:
// types/config.d.ts (auto-generated from your JSON files)
declare module '@nextnode/config-manager' {
interface UserConfigSchema {
app: {
name: string
version: string
features: string[]
environment: string
}
email: {
provider: 'resend' | 'nodemailer' // Inferred from your actual values
from: string
to: string
replyTo?: string // Optional if null in any config
templates: {
projectRequest: {
subject: string
companyName: string
websiteUrl: string
companyLogo?: string
}
}
}
}
}
// Now your code has perfect type safety:
const config = getConfig() // Fully typed!
const provider = getConfig('email.provider') // 'resend' | 'nodemailer'Manual Module Augmentation (Advanced)
For even more precise types, you can manually declare your configuration schema:
// In your project, create a types/config.d.ts file:
declare module '@nextnode/config-manager' {
interface UserConfigSchema {
app: {
name: string
version: string
features: ('auth' | 'analytics' | 'payments')[] // Specific union types
environment: 'development' | 'staging' | 'production'
debug?: boolean
}
email: {
provider: 'sendgrid' | 'resend' | 'mock'
from: string
to: string
apiKey?: string // Only in production
}
database: {
host: string
port: number
ssl: boolean
credentials: {
username: string
password: string
}
}
}
}Environment Detection
The configuration system automatically detects the environment in this order:
environmentoption passed toinitConfig()NODE_ENVenvironment variable- Defaults to
'development'
Configuration Loading Priority
Configurations are merged in this order (later configs override earlier ones):
default.json- Base configuration{environment}.json- Environment-specific configurationlocal.json- Local overrides (git-ignored, optional)
Best Practices
1. Leverage Automatic Type Generation 🚀
// ✅ RECOMMENDED: Let the library handle types automatically
initConfig({ configDir: './config' })
const emailConfig = getConfig('email') // Perfectly typed!
const dbHost = getConfig('database.host') // string
// ❌ AVOID: Manual type annotations (unless needed for specific unions)
const emailConfig = getConfig<EmailConfig>('email')2. Organize Configuration by Feature
{
"database": {
"host": "localhost",
"port": 5432,
"ssl": false
},
"redis": {
"host": "localhost",
"port": 6379
},
"email": {
"provider": "resend",
"from": "[email protected]"
},
"features": {
"authentication": true,
"analytics": false,
"payments": true
}
}3. Use Environment Variables for Secrets
{
"database": {
"password": "${DATABASE_PASSWORD}"
},
"email": {
"apiKey": "${EMAIL_API_KEY}"
},
"auth": {
"jwtSecret": "${JWT_SECRET}"
}
}4. Validate Required Configuration at Startup
// ✅ With automatic type inference, validation is easier
const validation = validateRequiredConfig([
'database.host',
'database.password',
'email.apiKey',
'auth.jwtSecret',
])
if (!validation.valid) {
console.error('Missing required configuration:', validation.missing)
process.exit(1)
}
// ✅ Direct access with confidence (no optional chaining needed)
const config = getConfig()
console.log(`Connecting to ${config.database.host}:${config.database.port}`)5. Handle Configuration Errors Gracefully
// ✅ The library now propagates meaningful errors
try {
await initConfig({ configDir: './config' })
} catch (error) {
// You'll get specific error messages for:
// - Missing config directory
// - Invalid JSON syntax
// - Configuration validation failures
// - Type generation issues
console.error('Configuration initialization failed:', error.message)
process.exit(1)
}6. Structure for Multiple Environments
config/
├── default.json # Base configuration
├── development.json # Development overrides
├── staging.json # Staging environment
├── production.json # Production environment
├── test.json # Test environment
└── local.json # Git-ignored local overridesTroubleshooting
Configuration Not Found
- Verify the config directory path
- Check file naming (must match environment name)
- Ensure JSON syntax is valid
Type Errors
- Ensure TypeScript types match your configuration structure
- Use generic types for custom configuration schemas
- Check that optional fields are properly marked
Environment Issues
- Verify
NODE_ENVis set correctly - Use
getEnvironment()to debug current environment - Check
getAvailableEnvironments()for valid options
Error Handling
- The library uses modern error propagation patterns
- Errors are no longer silently swallowed - you'll see meaningful messages
- Configuration and type generation failures surface with specific details
- Use try-catch blocks around
initConfig()for graceful error handling
Contributing
We welcome contributions! Please ensure your code:
- Follows TypeScript best practices
- Includes proper type definitions
- Has comprehensive test coverage
- Follows the existing code style
Development
# Install dependencies
pnpm install
# Generate config types from test fixtures
pnpm generate-test-types
# Run tests with full coverage
pnpm test
# Type checking (includes test type generation)
pnpm type-check
# Linting
pnpm lint
# Build the library
pnpm build
# Format code
pnpm format
# Manual type generation for config directory
pnpm generate-config-types [configDir] [outputFile]Development Workflow
- Type Generation: The library includes automatic type generation for both library development and user projects
- Test Types: Run
pnpm generate-test-typesto generate types from test fixtures - Type Safety: The
type-checkscript automatically generates test types before checking - Continuous Integration: All scripts are designed to work in CI environments
Working with Generated Types
During development, you may need to regenerate types:
# Regenerate types from your project's config files
node src/generate-types.js ./config ./types/config.d.ts
# Or use the npm script for test fixtures
pnpm generate-test-typesLicense
ISC
