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 🙏

© 2024 – Pkg Stats / Ryan Hefner

tconf

v3.1.0

Published

Heirarchical configuration with environment variable coercion and type validation.

Downloads

264

Readme

tconf


Version Downloads/month License

Adapting 12 factor app configuration to a type checked, application focused world view.

Features

  • Hierarchical configuration - values are merged from multiple sources.
  • Supported file formats: yaml, json, json5
  • Environment specific configuration via NODE_ENV
  • Runtime type validation.
  • Support for modulare configuration.
  • Type coercion of environment variables - string values can be converted to:
    • number
    • boolean
    • Date
    • RegExp
    • Array<number|boolean|Date|RegExp>
  • All values can implicitly be configured by environment variables.

Overview

12 factor app guidelines for configuration promotes "strict separation of config from code" through the use of environment variables. While this is beneficial from a deployment perspective, how this is implemented in many cases falls short of adequately supporting complex configuration within an application.

Typical approaches involve referencing process.env directly, perhaps with additional support through a library like dotenv. These applications often start by working with a flat list of variables.

const {
    DB_HOST,
    DB_USERNAME,
    DB_PASSWORD,
    // ...
} = process.env;

As configuration becomes more complex, this flat structure becomes cumbersome to deal with and to reason about. To combat this, developers will organize their configuration into a hierarchical structure. Having to map from a flat list of env vars into a desired shape, performing type coercion from env var strings, and executing validation is often an exercise left for the developer. For example, a desired end state for your configuration might look like:

api: {
  baseUrl: string
  port?: number
  debugMode?: boolean
  auth: {
    secret: string
  }
}
database: {
  host: string
  username: string
  password: string
  driverOpts?: {
    connectionTimeout?: number
    queryTimeout?: number
  }
}
...

Representing this as a flat list of env vars is not an effective way to work with your configuration. tconf addresses this by allowing authors to specify the desired shape and type of their configuration and performs mapping and coercion from environment variables automatically.

Getting Started

1. install

npm install tconf

2. create config specification (optional)

tconf utilizes runtypes for runtime type checking and as a schema for your config. This represents what you want your config to look like.

// src/config.ts
import { Boolean, Optional, Record, Static, String } from 'runtypes';

const ApiConfig = Record({  
    port: number,
    debug: Optional(Boolean)
})
const DatabaseConfig = Record({
  host: String,
  username: String,
  password: Optional(String)
})

const Config = Record({
    api: ApiConfig,
    database: DatabaseConfig
});
export type Config = Static<typeof Config>;

where the type Config is inferred as:

interface Config {
  api: {
    port: number
    debug?: boolean
  },
  database: {
    host: string
    username: string
    password?: string
  }
}

If you aren't using TypeScript or don't care about having your configuration statically typed, coerced, and validated then you can skip this.

3. map to env var names (optional)

Create a config file that defines a mapping of env vars. tconf provides support for template variables that can be used for env var interpolation (similar to docker compose) and also allows for assigning default values.

# config/env.yaml
api:
  port: ${API_PORT:3000}
database:
  host: ${DB_HOST:"db.domain.com"}
  username: ${DB_USER}
  password: ${DB_PASSWORD}

This is also optional. tconf natively supports configuration mapping from environment variables following a path naming convention. (you can set any configuration value using an environment variable). Use interpolation variables in your config only if you need to map from some specifically named variable that doesn't match your config.

4. load your configuration

// src/config.ts
import { initialize } from 'tconf'

const tconf = initialize({
  // directories containing configuration files
  path: path.join(__dirname, '..', 'config'),
  // the runtypes Config object (optional)
  schema: Config,
  // sources to look for config, in this case the files
  // default.yaml, ${NODE_ENV}.yaml, and env.yaml
  sources: ['default', 'NODE_ENV', 'env'],
})
export default tconf.get();

tconf will import configurations from the defined sources (or a set of defaults) from the specified directories, and merge the values in the order of the specified sources.

5. use it

// src/foo.ts
import config from './config'
import dbConnect from './db'

const conn = await dbConnect(config.database);

6. use in isolated modules

Within larger applications, you may want to isolate certain areas of your code into modules. It may make sense to isolate your configuration to such modules as well.

First, expose your initialized Tconf instance:

// src/config.ts
import { initialize } from 'tconf'

export const tconf = initialize({ // <-- export the instance
    // ...
})
export default tconf.get(); // exports the configuration

Then in your module, register your configuration schema and provide access to your module.

// src/modules/db/config.ts
import {tconf} from '../../config'

const Config = Record({
    uri: String
})

const config = tconf.register('database', Config); // Static<typeof Config>

export default config

The configuration will be sourced the same way, but you'll need to add your configuration under the registered name.

# config/default.yaml
api:
  # //...

database:
  uri: postgresql://host.com:5432/appdb

Documentation

Please see the documentation for more detailed information and capabilities of tconf.