env-interpolation
v1.1.1
Published
A lightweight, zero-dependency utility for recursively interpolating ${VAR:default} placeholders in strings, objects, and arrays.
Maintainers
Readme
env-interpolation
Recursively resolve ${VAR} style placeholders in strings, objects, or arrays using environment variables or custom maps.
Features
- Works with strings, plain objects, and arrays without mutating the original input.
- Falls back to
process.envautomatically; pass your own variable map for custom contexts. - Supports defaults (
${NAME:Guest}) including quoted values and nested placeholders. - Handles nested interpolation across multiple passes while preventing infinite loops.
- Escape placeholders with backslashes (
\\${VAR}) or disable escaping entirely when needed. - Ships with full TypeScript definitions and preserves the structural type of the input.
Installation
npm install env-interpolation
# or
yarn add env-interpolation
# or
pnpm add env-interpolationRequirements:
- Node.js 18 or higher
- Supports both ESM (
import) and CommonJS (require)
Quick Start
ESM (import)
import { interpolate } from "env-interpolation";
const greeting = interpolate("Hello ${NAME:Guest}!", { NAME: "Ada" });
// "Hello Ada!"
const config = interpolate({
url: "${API_URL:https://api.example.com}",
timeout: "${TIMEOUT:5000}",
features: ["${FEATURE_PRIMARY:alpha}", "${FEATURE_SECONDARY:beta}"],
});
// All placeholders resolved using process.env by defaultCommonJS (require)
const { interpolate } = require("env-interpolation");
const greeting = interpolate("Hello ${NAME:Guest}!", { NAME: "Ada" });
// "Hello Ada!"
const config = interpolate({
url: "${API_URL:https://api.example.com}",
timeout: "${TIMEOUT:5000}",
features: ["${FEATURE_PRIMARY:alpha}", "${FEATURE_SECONDARY:beta}"],
});
// All placeholders resolved using process.env by defaultPlaceholder syntax
${VAR}— looks upVARin the variable map orprocess.env.${VAR:Default}— usesDefaultwhenVARis missing orundefined.${VAR:'Quoted value'}or${VAR:"Quoted value"}— quotes let you keep colons or other placeholders in defaults. Both single and double quotes are stripped.- Invalid variable names (anything beyond letters, numbers, and
_) are left untouched. - Defaults can contain nested placeholders; they are resolved in subsequent passes.
API
interpolate<T>(content, variables?, options?)
content(T extends string | Record<string, unknown> | unknown[]): value (or structure) to process.variables(Record<string, string | undefined>): optional override map. Defaults toprocess.envwhen available.options:escape(boolean, defaulttrue): when enabled, a single preceding backslash escapes a placeholder (\\${VAR}→${VAR}). Disable to treat backslashes as literal characters.maxPasses(number, default10): maximum interpolation passes. Lower to cap work on pathological nesting; raise to resolve deeper chains.
Returns the interpolated value while preserving the original shape and TypeScript type.
Behavior notes
- Resolution runs up to 10 passes to support nesting while protecting against infinite substitution loops.
- Empty defaults (
${VAR:}) leave the placeholder intact so you can detect missing configuration. - Arrays and objects are traversed deeply; non-string primitives are returned untouched.
Escaping examples
import { interpolate } from "env-interpolation";
interpolate("Literal \\${PASSWORD}");
// "Literal ${PASSWORD}" (escape enabled, the placeholder is left as-is)
interpolate("Literal \\${PASSWORD}", { PASSWORD: "secret" }, { escape: false });
// "Literal \\secret" (escape disabled, placeholder still resolves)TypeScript aware
The exported function is fully typed. The returned value retains the structural type of the input, so narrowed types stay intact:
import { interpolate } from "env-interpolation";
const settings = {
port: "${PORT:3000}",
flags: ["${PRIMARY_FLAG:enabled}", "${SECONDARY_FLAG:disabled}"],
} as const;
const result = interpolate(settings);
// result has the same readonly structure as `settings`Security Considerations
⚠️ Warning: Interpolating secrets into logs or HTML can leak sensitive information. Prefer resolving variables at the application edge and redacting secrets in logs.
Browser Usage
Since process.env isn't available in browsers, pass variables explicitly:
import { interpolate } from "env-interpolation";
const config = {
apiUrl: "${API_URL:https://api.example.com}",
timeout: "${TIMEOUT:5000}",
};
const result = interpolate(config, {
API_URL: "https://prod-api.example.com",
TIMEOUT: "10000",
});Testing & development
npm run test– run the Vitest suite (covers string, object, and array interpolation).npm run lint– lint sources with ESLint.npm run build– produce the bundled output via tsup.
Contributing
Contributions and bug reports are welcome! Read the CONTRIBUTING.md guide and adhere to the CODE_OF_CONDUCT.md when participating. Issues and pull requests live at the GitHub repository.
License
Released under the MIT License.
