Recipes
Idiomatic compositions using @mongez/config.
Multi-source boot
Layer base + env + per-deploy overrides. Object-form set deep-merges, so the order of calls determines the precedence (last wins for any given key):
import config from "@mongez/config";import baseConfig from "./config/base";import envConfig from "./config/env";
config.set(baseConfig);config.set(envConfig);
// Single-key overrides at the end.if (process.env.API_URL) { config.set("api.url", process.env.API_URL);}if (process.env.LOG_LEVEL) { config.set("logging.level", process.env.LOG_LEVEL);}Feature flags with safe defaults
import config from "@mongez/config";
function isEnabled(feature: string): boolean { return Boolean(config.get(`features.${feature}`, false));}
// Booted somewhere as:// config.set({ features: { darkMode: true, beta: false } });
if (isEnabled("darkMode")) { // ...}if (isEnabled("brandNew")) { // false — never configured, default kicks in}The Boolean(...) wrapper coerces any truthy value (string, number) to a boolean — useful if your feature flags are sourced from env vars ("true" / "1" / "").
Default-with-explicit-undefined-trap
const timeoutMs = config.get("api.timeout", 30000);fetch(url, { signal: AbortSignal.timeout(timeoutMs) });Works even when api.timeout was never set; falls back to 30000. Note that if you (or some other module) explicitly did config.set("api.timeout", undefined), you’d still get the fallback.
Env-driven config
import config from "@mongez/config";
config.set({ api: { url: process.env.API_URL ?? "http://localhost:3000", timeout: Number(process.env.API_TIMEOUT ?? 5000), }, features: { darkMode: process.env.DARK_MODE === "true", beta: process.env.NODE_ENV !== "production", },});Reactive config (via @mongez/atom)
This package doesn’t fire events. If you need reactivity, seed an atom from config and subscribe to the atom:
import config from "@mongez/config";import { createAtom } from "@mongez/atom";
const themeAtom = createAtom({ key: "ui.theme", default: config.get("features.defaultTheme", "light"),});
themeAtom.onChange((next) => { document.documentElement.dataset.theme = next as string;});
// Later: write to the atom, not back to config.themeAtom.update("dark");Treat config as boot-time / read-only at runtime, and reactive state as separate.
Per-feature config namespaces
import config from "@mongez/config";
export function apiConfig() { return { url: config.get("api.url") as string, timeout: config.get("api.timeout", 5000) as number, headers: config.get("api.headers", {}) as Record<string, string>, };}
// usageimport { apiConfig } from "./config/api";const { url, timeout } = apiConfig();Snapshot at boot for debugging
import config from "@mongez/config";
if (process.env.NODE_ENV !== "production") { // Clone so later mutations don't change the dump. const snapshot = structuredClone(config.list()); console.log("[config booted]", snapshot);}