0.1.0 • Published 5 months ago

@jungvonmatt/config-loader v0.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

@jungvonmatt/config-loader

npm version build status coverage sonarcloud status

Load configuration from files, environment variables, and interactively prompt for missing values

A flexible configuration loader that combines multiple configuration sources with interactive prompts for missing required values. Inspired by c12, built on top of cosmiconfig and jiti with additional features for environment variable mapping and user prompts.

Features

  • 🔍 Multiple config sources: Load from package.json, rc files, config files, and more
  • 🌍 Environment variable support: Automatic dotenv loading and environment variable mapping
  • 💬 Interactive prompts: Ask users for missing required configuration values
  • 🔄 Config merging: Smart merging of configuration from multiple sources with overrides
  • 📁 Flexible file formats: Support for JSON, YAML, JS, TS, and more
  • 🛡️ TypeScript support: Full TypeScript support with type safety

Installation

# ✨ Auto-detect (supports npm, yarn, pnpm, deno and bun)
npx nypm install @jungvonmatt/config-loader

Usage

ESM (Node.js, Bun, Deno)

import { loadConfig } from "@jungvonmatt/config-loader";

Basic Example

import { loadConfig } from "@jungvonmatt/config-loader";

const { config } = await loadConfig({
  name: "myapp",
  defaultConfig: {
    port: 3000,
    host: "localhost",
  },
});

console.log(config.port); // 3000

With Required Fields and Prompts

import { loadConfig } from "@jungvonmatt/config-loader";

const { config } = await loadConfig({
  name: "myapp",
  required: ["apiKey", "databaseUrl"],
  prompts: [
    {
      name: "apiKey",
      type: "password",
      message: "Enter your API key:",
    },
    {
      name: "databaseUrl",
      type: "input",
      message: "Enter database URL:",
    },
  ],
});

Environment Variable Mapping

const { config } = await loadConfig({
  name: "myapp",
  envMap: {
    DATABASE_URL: "databaseUrl",
    API_KEY: "apiKey",
    PORT: "port",
  },
  defaultConfig: {
    port: 3000,
  },
});

Configuration Files

The loader searches for configuration in the following locations (in order):

  • package.json (in a myapp property)
  • .myapprc
  • .myapprc.json
  • .myapprc.yaml / .myapprc.yml
  • .myapprc.js / .myapprc.ts / .myapprc.mjs / .myapprc.cjs
  • .config/.myapprc.*
  • myapp.config.js / myapp.config.ts / myapp.config.mjs / myapp.config.cjs

Where myapp is the name you provide in the options.

Example Config Files

.myapprc.json

{
  "port": 8080,
  "database": {
    "url": "postgresql://localhost/mydb"
  }
}

myapp.config.js

export default {
  port: process.env.PORT || 3000,
  database: {
    url: process.env.DATABASE_URL,
  },
};

Environment Variables

Automatic Environment Loading

Environment variables are automatically loaded from .env files:

  • .env.{NODE_ENV} (e.g., .env.production)
  • .env

Configuration Override Pattern

Any configuration can be overridden using environment variables with the pattern:

{NAME}_CONFIG_{PATH}

For example, with name: "myapp":

  • MYAPP_CONFIG_PORT=8080 sets config.port = 8080
  • MYAPP_CONFIG_DATABASE_URL=... sets config.databaseUrl = ...

API

loadConfig<T>(options: LoadConfigOptions<T>): Promise<CosmiconfigResult<T>>

Options

OptionTypeDefaultDescription
namestringRequiredName of the configuration (used for file searching)
searchStrategySearchStrategy"global"Search strategy for finding config files. Can be "global" or "project"
searchPlacesstring[]See belowArray of file paths/patterns to search for config files
defaultConfigPartial<T>{}Default configuration values
overridesPartial<T>{}Configuration overrides (highest priority)
requiredArray<keyof T>[]Array of required configuration keys
envMapRecord<string, keyof T>{}Map environment variable names to config keys
dotenvbooleantrueWhether to load .env files
envNamestring \| falseprocess.env.NODE_ENVEnvironment name for .env.{envName} file
cwdstringprocess.cwd()Working directory for file searching
configFilestringundefinedPath to a specific config file to load
promptsPromptOptions[] \| ((config: T) => PromptOptions[])[]Interactive prompts for missing values. See enquirer for syntax details

Default Search Places

When searchPlaces is not specified, the following locations are searched (where {name} is your config name):

  • package.json
  • .{name}rc
  • .{name}rc.json
  • .{name}rc.yaml / .{name}rc.yml
  • .{name}rc.js / .{name}rc.ts / .{name}rc.mjs / .{name}rc.cjs
  • .config/.{name}rc
  • .config/.{name}rc.json
  • .config/.{name}rc.yaml / .config/.{name}rc.yml
  • .config/.{name}rc.js / .config/.{name}rc.ts / .config/.{name}rc.mjs / .config/.{name}rc.cjs
  • {name}.config.js / {name}.config.ts / {name}.config.mjs / {name}.config.cjs

Returns

interface ConfigLoaderResult<T> {
  config: T; // The merged configuration object
  filepath: string; // Path to the config file that was loaded
  isEmpty: boolean; // Whether the config file was empty
}

Prompt Options

Prompts use enquirer under the hood:

interface PromptOptions {
  name: string; // Configuration key name
  type: string; // Prompt type: 'input', 'password', 'select', etc.
  message: string; // Prompt message
  choices?: string[]; // For select/multiselect prompts
  initial?: any; // Default value
  // ... other enquirer options
}

Examples

Complete Application Setup

import { loadConfig } from '@jungvonmatt/config-loader'

interface AppConfig {
  port: number
  host: string
  database: {
    url: string
    pool: number
  }
  apiKey: string
  features: string[]
}

const { config } = await loadConfig<AppConfig>({
  name: 'myapp',

  // Default values
  defaultConfig: {
    port: 3000,
    host: 'localhost',
    database: {
      pool: 10
    },
    features: []
  },

  // Required fields that must be provided
  required: ['databaseUrl', 'apiKey'],

  // Map environment variables
  envMap: {
    'DATABASE_URL': 'databaseUrl',
    'API_KEY': 'apiKey',
    'PORT': 'port'
  },

  // Interactive prompts for missing required values
  prompts: [
    {
      name: 'databaseUrl',
      type: 'input',
      message: 'Database connection URL:',
      initial: 'postgresql://localhost:5432/myapp'
    },
    {
      name: 'apiKey',
      type: 'password',
      message: 'API Key:'
    }
  ]
})

console.log(`Starting server on ${config.host}:${config.port}`)

Development

  • Clone this repository
  • Install latest LTS version of Node.js
  • Enable Corepack using corepack enable
  • Install dependencies using pnpm install
  • Run interactive tests using pnpm dev

License

Published under the MIT license. Made by Jung von Matt TECH 💚


🤖 auto updated with automd