Sources
Sources define where the library reads your configuration from, such as files or environment variables.
For loading source from files, use new FileSource('[file-name].[ext]')
:
import { ConfigBuilder, FileSource } from "@layerfig/config";
import { schema } from "./schema";
export const config = new ConfigBuilder({
validate: (finalConfig) => schema.parse(finalConfig),
})
.addSource(new FileSource("base.json"))
.build();
In this case, base.json
is a file located in the <root-project-dir>/config
directory (or the one specified via absoluteConfigFolderPath
).
Other File Extensions
Section titled “Other File Extensions”To support various project needs and preferences, we provide parsers for other common configuration file formats:
… or you can create your own parser.
Object
Section titled “Object”The ObjectSource
is a simple yet powerful tool for creating client-side configurations with Layerfig. It’s ideal when you want to avoid using files or need to override/debug your configuration. It also supports slots
, allowing you to use environment variables:
import { ConfigBuilder, ObjectSource } from "@layerfig/config/client";
import { schema } from "./schema";
export const config = new ConfigBuilder({
validate: (finalConfig) => schema.parse(finalConfig),
})
.addSource(
new ObjectSource({
baseURL: "$PUBLIC_BASE_URL",
randomValue: true,
})
)
.build();
Since a framework like Vite adds PUBLIC_*
environment variables to import.meta.env
and makes them available on the client, your config
object will contain all the type-checked values.
Environment Variables
Section titled “Environment Variables”Consider the following scenario:
Your application’s configuration files are committed to version control and used to build a Docker image for production. When running this image locally for debugging, any change to a configuration value requires rebuilding the image. This process can be slow and results in testing a modified image rather than the actual production build.
To avoid this, use EnvironmentVariableSource
to override configuration values at runtime without modifying the source files:
import {
ConfigBuilder,
FileSource,
EnvironmentVariableSource,
} from "@layerfig/config";
import { schema } from "./schema";
export const config = new ConfigBuilder({
validate: (finalConfig) => schema.parse(finalConfig),
})
.addSource(new FileSource("base.json"))
.addSource(new EnvironmentVariableSource())
.build();
By default, the library expects environment variables with the following structure:
- Prefix:
"APP"
- Prefix separator:
"_"
- Nested key separator:
"__"
For example, the environment variable APP_port
overrides the port
key in your configuration.
Example Usage
Section titled “Example Usage”Suppose your base.json
contains:
{
"appURL": "http://localhost:4444",
"port": 4444,
"appEnv": "local"
}
Define your schema and load the sources:
import { ConfigBuilder, FileSource } from "@layerfig/config";
export const config = new ConfigBuilder({
validate: (finalConfig, z) => {
const schema = z.object({
appURL: z.url(),
port: z.coerce.number().check(z.int(), z.positive()),
appEnv: z.enum(["local", "dev", "prod"]),
});
return schema.parse(finalConfig);
},
})
.addSource(new FileSource("base.json"))
.addSource(new EnvironmentVariableSource())
.build();
Run the application with overrides:
APP_appEnv=prod node index.js
Since the environment variable source is added last, its values take precedence.
Overriding Nested Objects
Section titled “Overriding Nested Objects”Use __
(double underscores) as a separator to target nested keys:
import {
ConfigBuilder,
FileSource,
EnvironmentVariableSource,
z,
} from "@layerfig/config";
const schema = z.object({
api: z.object({
vendor: z.object({
aws: z.object({
apiToken: z.string(),
}),
}),
}),
});
const config = new ConfigBuilder({
validate: (finalConfig) => schema.parse(finalConfig),
})
.addSource(new FileSource("base.json"))
.addSource(new EnvironmentVariableSource())
.build();
APP_api__vendor__aws__apiToken=12345 node index.js
Customizing Environment Variable Settings
Section titled “Customizing Environment Variable Settings”You can customize the prefix, prefix separator, and nested-key separator:
import { ConfigBuilder, FileSource } from "@layerfig/config";
import { schema } from "./schema";
const config = new ConfigBuilder({
validate: (finalConfig) => schema.parse(finalConfig),
})
.addSource(new FileSource("base.json"))
.addSource(
new EnvironmentVariableSource({
prefix: "VULCAN",
prefixSeparator: "--",
separator: "----",
})
)
.build();
VULCAN--api----vendor----aws----apiToken=12345 node index.js