Configuration helper for TypeScript applications.
It acts as a gateway to your configuration, allowing it to be defined in various ways but used only in a single, type-safe manner.
No dependencies, ESM only.
Configate supports:
ts
, js
and json
formatsNODE_ENV
environment variable (or the provided environment name)To install Configate, use your preferred package manager:
npm install configate
Use the loadConfig
function once, to load and merge configurations from specified directories.
With parameters you can define:
configDirs
: (Default: ['${current-working-directory}/config']
) An array of directories to load configurations fromenvironment
: (Default: process.env.NODE_ENV
) The environment to load specific configurations forfileExtensions
: (Default: ['ts', 'js']
) An array of file extensions to load configurations fromthrowOnUndefinedProp
: (Default: true
) If true, throws an error when accessing undefined propertiesfreezeConfig
: (Default: true
) If true, freezes the configuration object to make it immutable// src/config.ts import { loadConfig } from 'configate'; export const { config } = await loadConfig<YourConfigStructure>(); export type YourConfigStructure = { database: { host: string; port: number; password: string }; };
Use this src/config.ts
anywhere in your application to access the configuration object just like this:
// src/app.ts import { config } from './config.ts'; const database = dbClient({ host: config.database.host, port: config.database.port, password: config.database.password, });
config
directory in your project.default.ts
file in config
directory and export a config
object with default values.// config/default.ts import type { YourConfigStructure } from '../src/config.ts'; export const config: YourConfigStructure = { database: { host: 'localhost', port: 5432, password: '' }, };
That's it 🎉
Environments can be named for example development
, staging
, production
but you can use any names you want.
Create for example production.ts
file in config
directory and export a config
object.
DeepPartial
type to allow partial configuration, since usually you just want to override some properties.NODE_ENV
environment variable is set to production
.// config/production.ts import type { DeepPartial } from 'configate'; import type { YourConfigStructure } from '../src/config.ts'; export const config: DeepPartial<YourConfigStructure> = { database: { host: 'database-production-server.com', }, };
Do the same for other environments if you need to override more properties for them.
When you need to define secrets in configuration, they should be defined via environment variables.
Create custom-environment-variables.ts
file in config
directory and export a config
object.
process.env
to read environment variables and assign to property in your configuration// config/custom-environment-variables.ts import type { DeepPartial } from 'configate'; import type { YourConfigStructure } from '../src/config.ts'; export const config: DeepPartial<YourConfigStructure> = { database: { password: process.env.DATABASE_PASSWORD, }, };
Local configuration files are not committed to the repository and are used for local development only. Use them to override some configuration when running the application locally.
Supported variants:
local.ts
- always loadedlocal-{environment}.ts
- local, environment-specific config. Example: local-development.ts
NODE_ENV
is set or environment
parameter is provided to loadConfig
functionAdd this to .gitignore
to prevent committing local configuration files:
**/config/local*
default.ext {environment}.ext local.ext local-{environment}.ext custom-environment-variables.ext
Sometimes you may need to use configuration which doesn't throw on undefined properties,
for example when you want to pass part of it to some external module and it will try to read unknown properties.
But you shouldn't set throwOnUndefinedProp: false
to just handle this case.
For this reason, the unsecureConfig
object is also returned from loadConfig
function, alongside the config
object.
// src/config.ts import { loadConfig } from 'configate'; export const { config, unsecureConfig } = await loadConfig(); someExternalModule(unsecureConfig.database); // It won't throw error if external module tries to read e.g. `unsecureConfig.database.user` property
If you want to import src/config.ts
with absolute path, define:
// package.json { "imports": { "#config": "./src/config.ts" } }
and
// tsconfig.json { "compilerOptions": { "paths": { "#config": ["./src/config.ts"] } } }
and then import it like this:
import { config } from '#config'; const host = config.database.host;
import { loadConfig } from 'configate'; export const { config } = await loadConfig<TestConfig>({ configDirs: [ `${import.meta.dirname}/../../someParentConfigDirectory`, `${import.meta.dirname}/../config`, ], });
Add Package
deno add jsr:@drob/configate
Import symbol
import * as configate from "@drob/configate";
---- OR ----
Import directly with a jsr specifier
import * as configate from "jsr:@drob/configate";
Add Package
npx jsr add @drob/configate
Import symbol
import * as configate from "@drob/configate";
Add Package
yarn dlx jsr add @drob/configate
Import symbol
import * as configate from "@drob/configate";
Add Package
pnpm dlx jsr add @drob/configate
Import symbol
import * as configate from "@drob/configate";
Add Package
bunx jsr add @drob/configate
Import symbol
import * as configate from "@drob/configate";