Skip to content

Dynamic Environment

If you maintain multiple environments (e.g., local, dev, staging, prod), you’ll have a separate configuration file for each one.

However, you can’t load them all at once:

import { ConfigBuilder, FileSource } from "@layerfig/config";
import { schema } from "./schema";

export const config = new ConfigBuilder({
  validate: (finalConfig) => schema.parse(finalConfig),
})
  .addSource(new FileSource("base.jsonc"))
  .addSource(new FileSource("local.jsonc"))
  .addSource(new FileSource("dev.jsonc"))
  .addSource(new FileSource("staging.jsonc"))
  .addSource(new FileSource("prod.jsonc"))
  .build();

This approach loads every file and merges them, with each subsequent layer overriding the previous.

A better solution is to use an environment variable (for example, APP_ENV=local|dev|staging|prod) and name your files accordingly:

import { ConfigBuilder, FileSource } from "@layerfig/config";
import { schema } from "./schema";

const appEnv = process.env.APP_ENV ?? "local";

export const config = new ConfigBuilder({
  validate: (finalConfig) => schema.parse(finalConfig),
})
  .addSource(new FileSource("base.jsonc"))
  .addSource(new FileSource(`${appEnv}.jsonc`))
  .build();

Now, when you run your application with different APP_ENV values, it automatically loads the matching configuration file.

If only a known set of names is valid, validate the variable itself so a typo fails with a message that says what is wrong:

const APP_ENVS = ["local", "dev", "staging", "prod"] as const;

const appEnv = process.env.APP_ENV ?? "local";

if (!APP_ENVS.includes(appEnv as (typeof APP_ENVS)[number])) {
  throw new Error(
    `Unknown APP_ENV "${appEnv}". Expected one of: ${APP_ENVS.join(", ")}`
  );
}