FeathersJS production.json: duplicate full nested objects or switch to a custom deep-merge config setup?
0 reputation · 21 Feb 2020, 03:38 UTC
0 reputation · 21 Feb 2020, 03:38 UTC
Our FeathersJS app relies on the npm config module with default.json defining a nested authentication object (JWT secret plus options like expiresIn and algorithm). In production we only want to override the secret, but the config module merges shallowly: setting authentication.jwt.secret in production.json replaces the whole nested object, silently dropping the options. Locally everything works because default.json is complete on its own.
We see two documented directions and are unsure which to standardize on:
production.json, accepting duplication and the risk of drifting out of sync with default.json.Assume a recent FeathersJS 5 (Dove) app generated by the CLI, deployed to a container platform where NODE_ENV=production is set explicitly.
Is full duplication in production.json the intended pattern for the config module, or is a custom deep-merge layer the common practice in production FeathersJS deployments? If we keep the stock module, is there a documented way to validate required nested keys at startup rather than discovering missing values at runtime? Are there known pitfalls with either approach when NODE_CONFIG_DIR differs between local and container environments?
35275 reputation · 21 Feb 2020, 08:17 UTC
For production FeathersJS (Dove) deployments, you should switch to a custom deep-merge configuration setup rather than duplicating nested objects. Full duplication in production.json is the default behavior of the config module, but it is not a recommended pattern for maintainable production apps due to the high risk of configuration drift.
The config npm module performs a shallow merge. When it encounters a key in production.json that already exists in default.json, it replaces the entire value. If that value is an object (like your authentication block), the entire object is swapped, erasing any nested keys not explicitly redefined in the production file.
To enable partial overrides and prevent runtime crashes, implement a merge and validation utility during the application bootstrap process (typically in src/app.ts or a dedicated config loader):
lodash.merge to handle the recursive combination of objects.config directly throughout the app, create a configuration provider that merges the config output with any necessary environment-specific overrides.app.listen(). This function should check for the existence of critical keys (e.g., config.get('authentication.jwt.secret')) and throw a hard Error if they are missing.// Example Validation Pattern
const requiredConfigs = ['authentication.jwt.secret', 'database.url'];
requiredConfigs.forEach(path => {
if (!config.has(path)) {
throw new Error(`Missing required configuration: ${path}`);
}
});
When NODE_CONFIG_DIR differs between local and container environments, the config module may fail to locate your files entirely. In containerized environments, ensure that your Dockerfile or compose file explicitly maps the config directory or sets the environment variable to an absolute path. If the module cannot find the directory, it may fallback to default.json without warning, which can lead to production apps attempting to connect to local development databases.
To refine this recommendation: Are you currently using environment variables (process.env) to inject secrets into production.json, or are the secrets stored as plaintext in the JSON file? If you are using environment variables, a custom wrapper is even more critical to ensure the mapping from ENV_VAR to config object is validated at boot.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.