Skip to content

Config

@strata-js/util-config is a configuration loading utility that supports YAML and JSON files with environment variable substitution and file includes. It stores named config objects and retrieves them with full TypeScript generics support.

Installation

bash
npm install @strata-js/util-config

Usage

typescript
import configUtil from '@strata-js/util-config';

interface AppConfig
{
    server : {
        host : string;
        port : number;
    };
    database : {
        connectionString : string;
    };
}

// Load a config file (typically at startup)
configUtil.load('./config.yml');

// Retrieve the parsed config anywhere in your application
const config = configUtil.get<AppConfig>();
console.log(config.server.port); // 8080

The default export is a singleton instance of ConfigUtil. You can also import the class directly if you need multiple independent instances:

typescript
import { ConfigUtil } from '@strata-js/util-config';

const myConfig = new ConfigUtil();
myConfig.load('./my-config.yml');

API

load(filePath, name?, options?)

typescript
configUtil.load(filePath : string, name ?: string, options ?: ConfigLoaderOptions) : void

Reads and parses a configuration file, storing the result under name.

ParameterTypeDefaultDescription
filePathstringPath to the config file. If not provided, uses the CONFIG_FILE environment variable.
namestring'default'Name to store the config under. Allows loading multiple config files.
optionsConfigLoaderOptionsSee belowOptions controlling parsing behavior.

Supported file formats are determined by extension:

ExtensionFormat
.yml, .yamlYAML
.jsonJSON

ConfigLoaderOptions

OptionTypeDefaultDescription
substituteEnvironmentVariablesbooleantrueReplace environment variable references in the file content before parsing.
mergeIncludesbooleantrueProcess include directives and merge included files into the config.

get<T>(name?)

typescript
configUtil.get<T>(name ?: string) : T

Returns the config stored under name. Throws an error if no config has been loaded under that name.

ParameterTypeDefaultDescription
namestring'default'The name the config was stored under during load() or set().

set<T>(config, name?)

typescript
configUtil.set<T extends Record<string, unknown>>(config : T, name ?: string) : void

Stores a config object directly, bypassing file loading. Useful for testing or when config comes from an external source.

ParameterTypeDefaultDescription
configTThe config object to store.
namestring'default'The name to store the config under.

delete(name?)

typescript
configUtil.delete(name ?: string) : void

Removes the config stored under name.

ParameterTypeDefaultDescription
namestring'default'The name of the config to remove.

clear()

typescript
configUtil.clear() : void

Removes all stored configs.

Environment Variable Substitution

When substituteEnvironmentVariables is enabled (the default), the file content is scanned for environment variable references before parsing. Three syntaxes are supported:

SyntaxExample
$VAR$HOSTNAME
${VAR}${REDIS_HOST}

If a referenced variable is not set, the reference is left as-is in the string.

yaml
# config.yml
server:
  host: "$HOSTNAME"
  port: 8080

database:
  connectionString: "postgres://${DB_USER}:${DB_PASS}@${DB_HOST}/mydb"

File Includes

Config files can include other files using the include key. Included files are loaded first, then the base file's values are merged on top (base values win).

Single include:

yaml
# config/local.yml
include: "base.yml"

service:
  serviceGroup: "MyService"

logging:
  level: debug
  prettyPrint: true

Multiple includes:

yaml
include:
  - "base.yml"
  - "logging-defaults.yml"

service:
  serviceGroup: "MyService"

Include paths are resolved relative to the file that contains the include directive. Includes can be nested up to 10 levels deep by default. Set the INCLUDE_DEPTH environment variable to change this limit.

Examples

Named Configs

Load separate configs for different parts of your application:

typescript
import configUtil from '@strata-js/util-config';

configUtil.load('./config/service.yml', 'service');
configUtil.load('./config/database.yml', 'database');

const serviceConfig = configUtil.get<ServiceConfig>('service');
const dbConfig = configUtil.get<DatabaseConfig>('database');

Environment-based Config Files

A common pattern is to load different files based on the current environment:

typescript
import configUtil from '@strata-js/util-config';

const env = process.env.ENVIRONMENT ?? 'local';
configUtil.load(`./config/${ env }.yml`);

const config = configUtil.get<AppConfig>();

Testing

Use set() to inject config directly in tests without touching the filesystem:

typescript
import configUtil from '@strata-js/util-config';

beforeEach(() =>
{
    configUtil.set({
        server: { host: 'localhost', port: 0 },
        database: { connectionString: 'sqlite::memory:' },
    });
});

afterEach(() =>
{
    configUtil.clear();
});

Base Config with Overrides

Use file includes to share common configuration across environments:

yaml
# config/base.yml
backend:
  type: "redis-streams"
  redis:
    host: "localhost"
    port: 6379
  discovery:
    enabled: true
yaml
# config/production.yml
include: "base.yml"

backend:
  redis:
    host: "$REDIS_HOST"
    password: "$REDIS_PASSWORD"

logging:
  level: info
  prettyPrint: false