Skip to content

Repository files navigation

ConfigBound

A type-safe configuration management library for TypeScript applications.

Features

  • Full Type Safety: Autocomplete for section and element names, with types inferred from your schema
  • Easy Validation: Validate all config at startup with validate() or get detailed error reports
  • Schema-Based: Define your configuration declaratively with Zod validators
  • Flexible Binds: Environment variables, files, or custom sources
  • Documentation Export: Generate JSON or YAML documentation from your config schema

Installation

npm install config-bound

Quick Start

import {
  ConfigBound,
  configItem,
  configEnum,
  configSection
} from '@config-bound/core';
import { EnvVarBind } from '@config-bound/core/binds/env';
import { z } from 'zod';

// Define your configuration schema with full type safety
const config = ConfigBound.createConfig(
  {
    port: configItem<number>({
      default: 3000,
      validator: z.number().int().min(0).max(65535),
      description: 'Application port'
    }),
    environment: configEnum({
      values: ['development', 'production'],
      default: 'development',
      description: 'Runtime environment'
    }),
    database: configSection(
      {
        host: configItem<string>({
          default: 'localhost',
          validator: z.string(),
          description: 'Database host'
        }),
        port: configItem<number>({
          default: 5432,
          validator: z.number().int().min(0).max(65535),
          description: 'Database port'
        })
      },
      'Database configuration'
    )
  },
  {
    binds: [await EnvVarBind.create({ prefix: 'MYAPP' })],
    validateOnInit: true // Catch config errors at startup!
  }
);

// Access values with full type safety - types are inferred, autocomplete works!
const port = config.get('app', 'port'); // TypeScript knows this is number
const env = config.get('app', 'environment'); // TypeScript knows this is "development" | "production"
const dbHost = config.get('database', 'host'); // TypeScript knows this is string

// Validate all config at once
try {
  config.validate();
  console.log('✅ All configuration is valid');
} catch (error) {
  console.error('❌ Configuration errors:', error);
}

Advanced: Imperative API

For advanced use cases where you need fine-grained control over construction, you can use the imperative API:

import { ConfigBound } from '@config-bound/core';
import { Section } from '@config-bound/core/section/section';
import { Element } from '@config-bound/core/element';
import { EnvVarBind } from '@config-bound/core/binds/env';

// Create configuration elements
const portElement = new Element<number>('port', 'Application port', 3000);
const logLevelElement = new Element<string>(
  'logLevel',
  'Logging level',
  'info'
);

// Create a configuration section
const appSection = new Section('app', [portElement, logLevelElement]);

// Create the config instance
const config = new ConfigBound(
  'app',
  [await EnvVarBind.create({ prefix: 'MYAPP' })],
  [appSection]
);

// Use it in your application (still fully type-safe!)
const port = config.get('app', 'port');

Note: The declarative createConfig API is recommended for most use cases.

Exporting Configuration Schema

ConfigBound provides schema export functionality through the @config-bound/schema-export package:

npm install @config-bound/schema-export
import {
  exportSchema,
  formatAsJSON,
  formatAsYAML
} from '@config-bound/schema-export';

// Get structured schema object
const schema = exportSchema(config.name, config.sections);

// Export as JSON
const json = formatAsJSON(schema);

// Export as YAML
const yaml = formatAsYAML(schema);

This is useful for:

  • Generating documentation automatically
  • Creating IDE autocomplete schemas
  • Validating environment variables
  • Building configuration UIs
  • API documentation

See the Export Documentation for detailed usage and examples.

Environment Variables

ConfigBound automatically maps configuration to environment variables using the EnvVarBind. By default, it uses a prefix to avoid conflicts:

const config = ConfigBound.createConfig(
  {
    /* your schema */
  },
  {
    binds: [await EnvVarBind.create({ prefix: 'MYAPP' })]
  }
);

This creates environment variables like:

  • MYAPP_APP_PORT for app.port
  • MYAPP_DATABASE_HOST for database.host
  • MYAPP_API_APIKEY for api.apiKey

Override values at runtime:

MYAPP_APP_PORT=8080
MYAPP_DATABASE_HOST=prod-db.example.com
MYAPP_API_APIKEY=your-secret-key

Static Values

Use StaticBind to inject values directly in code while still participating in bind priority order.

import { ConfigBound, configItem } from '@config-bound/core';
import { EnvVarBind } from '@config-bound/core/binds/env';
import { StaticBind } from '@config-bound/core/binds/static';
import { z } from 'zod';

const config = ConfigBound.createConfig(
  {
    port: configItem<number>({
      default: 3000,
      validator: z.number().int().min(0).max(65535)
    })
  },
  {
    // Earlier bind wins: StaticBind overrides EnvVarBind here.
    binds: [
      await StaticBind.create({ 'app.port': 8080 }),
      await EnvVarBind.create({ prefix: 'MYAPP' })
    ]
  }
);

StaticBind accepts either nested values ({ app: { port: 8080 } }) or flat dot-path keys ({ 'app.port': 8080 }).

Documentation

See the documentation site.

Examples

See the examples.

Development

This project uses Turbo for efficient task orchestration across workspaces.

Available Commands

# Build main package only
npm run build

# Build all packages (including examples)
npm run build:all

# Start development with watch mode
npm run dev

# Run all tests
npm run test

# Format all code
npm run format

# Lint all code
npm run lint

# Clean build artifacts
npm run clean

# Run CI checks (format, lint, test)
npm run check

# Run examples
npm run examples

# Run specific example
npm run start:envVarExample

Turbo Benefits

  • Caching: Turbo caches successful builds and tests for faster subsequent runs
  • Parallelization: Tasks run in parallel where possible
  • Dependency Management: Automatically builds dependencies before dependent tasks

Contributing

We welcome contributions! Please see CONTRIBUTING.md for details.

License

MIT License - see LICENSE for details.

About

Typescript configuration engine

Topics

Resources

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages