Load configuration from files, environment variables, and interactively prompt for missing values
A flexible configuration loader that extends c12 with additional features for environment variable mapping and interactive user prompts. Built on top of the unjs ecosystem for modern Node.js applications.
- π 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
- π Config extension: Built-in support for extending configurations from other files or remote sources
# β¨ Auto-detect (supports npm, yarn, pnpm, deno and bun)
npx nypm install @jungvonmatt/config-loaderESM (Node.js, Bun, Deno)
import { loadConfig } from "@jungvonmatt/config-loader";import { loadConfig } from "@jungvonmatt/config-loader";
const { config } = await loadConfig({
name: "myapp",
defaultConfig: {
port: 3000,
host: "localhost",
},
});
console.log(config.port); // 3000import { 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:",
},
],
});const { config } = await loadConfig({
name: "myapp",
envMap: {
DATABASE_URL: "databaseUrl",
API_KEY: "apiKey",
PORT: "port",
},
defaultConfig: {
port: 3000,
},
});// config.ts
export default {
extends: "./base.config.ts",
port: 8080,
database: {
url: "postgresql://localhost/mydb"
}
};
// base.config.ts
export default {
port: 3000,
host: "localhost",
database: {
url: "postgresql://localhost/default"
}
};The loader searches for configuration in the following locations (in order):
package.json(in amyappproperty).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.
.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 are automatically loaded from .env files:
.env.{NODE_ENV}(e.g.,.env.production).env
Any configuration can be overridden using environment variables with the pattern:
{NAME}_CONFIG_{PATH}
For example, with name: "myapp":
MYAPP_CONFIG_PORT=8080setsconfig.port = 8080MYAPP_CONFIG_DATABASE_URL=...setsconfig.databaseUrl = ...
Load configuration only from trusted directories and sources. JavaScript/TypeScript configs and c12 extensions execute code with your process permissions.
Dotenvx also supports command substitution in .env files. Set dotenv: false when dotenv loading is unnecessary.
Set globalRc: false to exclude user and workspace rc files; this option does not sandbox project configuration.
Validate the merged config with your application's schema before use. required checks key presence only.
Config values and returned layers can contain credentials. Redact them before logging, and use type: "password" for credential prompts.
| Option | Type | Default | Description |
|---|---|---|---|
name |
string |
Required | Name of the configuration (used for file searching) |
defaultConfig |
Partial<T> |
{} |
Default configuration values |
overrides |
Partial<T> |
{} |
Configuration overrides (highest priority) |
required |
Array<keyof T> | ((config: T) => Array<keyof T> | Promise<Array<keyof T>>) |
[] |
Array of required configuration keys or a function that returns them. The function receives the current config as an argument. |
envMap |
Record<string, keyof T> |
{} |
Map environment variable names to config keys |
dotenv |
boolean |
true |
Whether to load .env files |
envName |
string | false |
process.env.NODE_ENV |
Environment name for .env.{envName} file |
globalRc |
boolean |
true |
Whether to load user and workspace rc files in addition to project configuration |
cwd |
string |
process.cwd() |
Working directory for file searching |
configFile |
string |
undefined |
Path to a specific config file to load |
prompt |
Array<keyof T> | ((config: T) => Array<keyof T> | Promise<Array<keyof T>>) |
[] |
Array of configuration keys to prompt for, even if they exist in the config. Can be a function that returns the keys. Keys will be sorted based on the order in prompts if provided. |
prompts |
PromptOptions[] | ((config: T) => PromptOptions[]) |
[] |
Interactive prompts for missing values. See enquirer for syntax details. The order of prompts determines the order of fields in the prompt sequence. |
interface ResolvedConfig<T> {
config: T; // The merged configuration object
filepath: string | undefined; // Path to the config file that was loaded
missing: string[]; // Array of missing required fields
layers: Array<{
type: "module" | "file" | "env" | "overrides" | "default" | "prompt";
filepath: string | undefined;
config: Partial<T> | undefined;
cwd: string | undefined;
}>; // Array of configuration layers in order of application
}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
}Published under the MIT license.
Made by Jung von Matt TECH π
π€ auto updated with automd