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 🙏

© 2026 – Pkg Stats / Ryan Hefner

funtime-config

v1.0.0

Published

A modern TypeScript configuration library for Node.js and Deno

Downloads

3

Readme

Funtime-Config

Funtime-Config (Runtime-config but more Fun) is a configuration management tool designed to simplify the process of managing and deploying configurations across multiple environments. It follows the the principle of Parse, don't Validate where you create a configuration instance rather than just validate config data.

Installation

npm install funtime-config

Usage

Define your base application configuration. Your class should extend FuntimeConfig. This serves as both the interface and the default configuration for your application.

import { FuntimeConfig, IsString, IsBoolean } from "funtime-config";

class AppConfig extends FuntimeConfig {
  @IsString()
  PORT = 3000;
  
  @IsString()
  DB_HOST!: string;
  
  @IsBoolean()
  IS_TEST = false;
}

Notice that each property is decorated with a validation decorator. This is what enables runtime validation of your configuration. Internally this uses class-validator for the decorators.

Next, define your environment-specific configurations.

class DevConfig extends AppConfig {
  DB_HOST = "localhost";
}

class TestConfig extends AppConfig {
  IS_TEST = true;
  DB_HOST = "test.db";
}

class ProdConfig extends AppConfig {
  DB_HOST = "prod.db.server";
  PORT = 80;
}

Now you instantiate a loader, passing to it the env configs. The load() method will automatically detect the current environment via NODE_ENV.

const configLoader = new FuntimeConfigLoader<AppConfig>({
  configs: [DevConfig, ProdConfig, TestConfig],
});
const appConfig = await configLoader.load();

// process.env.NODE_ENV === 'dev' loads DevConfig
// process.env.NODE_ENV === 'prod' loads ProdConfig
// process.env.NODE_ENV === 'test' loads TestConfig

You can also explicitly specify the environment to load.

const configLoader = new FuntimeConfigLoader({ configs: [] });
const appConfig = await configLoader.load(ProdConfig);

Important

Notice that loading the config is an async operation. This likely means that you will need to bootstrap your application with async module loading.

// index.ts
import { getConfig } from "funtime-config";

const configLoader = new FuntimeConfigLoader({configs: []});
const appConfig = configLoader.load().then(async (config) => {
  const {default: app} = await import('./app.ts');
  app(appConfig);
});


// app.ts
export default function app(config: AppConfig) {
  // your app logic here

  // can accces the global config instance
  getConfig<YourAppConfig>();
}

Secret Management

Secrets such as passwords and API keys should NEVER be hardcoded in your configuration files. Instead, use environment variables or a secret management service to inject these values at runtime.

You have a few options.

(Preferred) Inject via environment variables

Your Funtime-Config will automatically read from environment variables that match the property names. Some other processes (e.g., Docker, Kubernetes, CI/CD pipelines) can inject these environment variables at runtime.

class AppConfig extends FuntimeConfig {
  @IsString()
  DB_PASSWORD = FuntimeSecretProperty<string>();
}

(Alternate) Resolve async properties

You can also define async properties that fetch values.

Notice that this is not reserved just for secrets and can be used for any property that requires async resolution.

class AppConfig extends FuntimeConfig {
  @IsString()
  DB_PASSWORD = FuntimeResolveProperty(async () => {
    // fetch from secret manager
    return await fetchDBSecret();
  });
  
  @IsNumber()
  PORT = 4242;  // default port
}

class ProdConfig extends AppConfig {
  PORT = FuntimeResolveProperty(async () => {
    // Notice that FuntimeResolveProperty can override default values too.
    
    // fetch from a remote config service
    return await fetchAvailablePort();
  });
}

ENV File Support

You can load environment variables from a .env file with the loader.

const configLoader = new FuntimeConfigLoader({
  configs: [],
  envFilePath: './path/to/.env',
});

This allows you to continue to use env variables in separate files while still leveraging Funtime-Config for validation.

# .test.env
API_URL=http://test.api.myapp.com
API_KEY=test

# .prod.env
API_URL=https://api.myapp.com
API_KEY=# THIS GETS INJECTED VIA A SECRET MANAGER

# .env
API_URL=http://localhost:3000
API_KEY=localdevkey123

Then in your config:

class AppConfig extends FuntimeConfig {
  @IsString()
  API_URL!: string;
  
  @IsString()
  API_KEY = FuntimeSecretProperty<string>();
}

const configLoader = new FuntimeConfigLoader<AppConfig>({
  configs: [AppConfig],
  envFilePath: process.env.NODE_ENV === 'local' ? true : `./.${process.env.NODE_ENV}.env`,
});
const appConfig = await configLoader.load();

By default, if envFilePath is set to true, it will look for a .env file in the current working directory. This can be disabled by setting envFilePath to false.

Local Development

When developing locally, you can create a LocalConfig class that won't be committed to source control (via gitignore). Specify the local config in the loader.

// local.config.ts (add this file to .gitignore)
export class LocalConfig extends FuntimeConfig {
  @IsString()
  API_URL = 'http://localhost:3000';
}

Then load it like so:

const configLoader = new FuntimeConfigLoader({
  configs: [...],
  localConfigPath: './local.config',
});

If the NODE_ENV is set to local, the loader will attempt to load the local config.