Configuration defines how both NodeKit and your application should work. There are a few ways to define configuration and a few ways to access it.
Configuration can be passed to the constructor or can be defined in separate directory as a set of files.
Basic example with a constructor:
const nodeKit = new NodeKit({config: {apiEndpoint: 'localhost:4242'}});
nodekit.ctx.log('My api endpoint', {endpoint: nodekit.ctx.config.myApiEndpoint}); // localhost:4242
You can place all your configuration in a file stored in separate directory and then pass path of that directory in the constructor:
// configs/common.ts
export default {apiEndpoint: 'localhost:4242'};
// app.ts
const nodeKit = new NodeKit({configsPath: path.resolve(__dirname, 'configs')});
nodekit.ctx.log('My api endpoint', {endpoint: nodekit.ctx.config.apiEndpoint}); // localhost:4242
NodeKit will read that directory and load configuration from the files in it.
Often apps have a number of diferent environments (like staging and production). NodeKit supports them too. In example below, NodeKit will determine current environment using APP_ENV
env variable and then merge resulting configuration using common and env-specific configuration files:
// configs/common.ts
export default {apiEndpoint: 'localhost:4242', someCommonValue: 322};
// configs/staging.ts
export default {apiEndpoint: 'staging.example.com'};
// configs/production.ts
export default {apiEndpoint: 'production.example.com'};
// process.env.APP_ENV is set to "staging"
// app.ts
const nodeKit = new NodeKit({configsPath: path.resolve(__dirname, 'configs')});
nodekit.ctx.log('Configuration', nodekit.config);
// {
// apiEndpoint: 'staging.example.com',
// someCommonValue: 322
// }
During configuration merge, Nodekit does not apply any kind of deep merge, just simple Object.assign
. Try to keep your configuration files flat and simple.
In some advanced cases your application can have not only environments but also different installations. For example, you can have one app separately deployed in two different departments, using different sets of configuration, each with it's own staging and production environments. Installations in NodeKit are used as another layer above environments and determined in runtime using APP_INSTALLATION
env varaible.
// configs/common.ts
export default {someCommonValue: 322};
// configs/department-one/staging.ts
export default {someCommonValue: 322};
// configs/department-one/production.ts
// ...
// configs/department-two/staging.ts
// ...
// configs/department-two/production.ts
// ...
Resulting configuration is merged in the following order (each line overriding previous):
- Default NodeKit config
- File configs (if
configsPath
is passed to the constructor)configs/common.ts
configs/<installation>/common.ts
- ifAPP_INSTALLATION
is presentconfigs/<env>.ts
- ifAPP_ENV
is presentconfigs/<installation>/<env>.ts
- ifAPP_INSTALLATION
is presentconfigs/<installation>/<env>.ts
- ifAPP_INSTALLATION
andAPP_ENV
are present
- Configuration object (if
config
is passed to the constructor)
nodekit.config.appDevMode
is defined by ENV variable APP_DEV_MODE
. It's used internally for things like prettifying logs in development mode, but you can also use it in your application when you need it.
We recommend to use appDevMode
instead of specific development "environment" or "installation" since logically it often carries purposes that can be applied to any environment.
appName
and appVersion
fields are used in places like logs to display what application they relate to.
They can be set in configuration and can be overrided with APP_NAME
and APP_VERSION
environment variables.
NodeKit is bundled with dotenv and it's activated by default in constructor.
Dotenv automatically parses .env
files in the directory and adds them to process.env
. It's very useful in development since you can keep secrets and dev-related overrides in .env
file, excluded from the repository history. Example:
// .env
API_TOKEN=123abc
API_ENDPOINT=localhost:3030/v1/
APP_DEV_MODE=1
// app.ts
const nodeKit = new NodeKit();
nodekit.ctx.log(process.env.API_TOKEN); // 123abc
To disable dotenv, pass an option to the constructor:
const nodeKit = new NodeKit({disableDotEnv: true});
You can access resulting configuration via NodeKit class instance or using any context:
// They are the same
ctx.log('My api endpoint', {endpoint: nodekit.config.apiEndpoint});
ctx.log('My api endpoint', {endpoint: ctx.config.apiEndpoint});
To use additional fields in configuration you should extend AppConfig interface:
declare module '@gravity-ui/nodekit' {
interface AppConfig {
myApiEndpoint: string;
}
}