Config Environment Variables Override
TODO: collapasable, copyable, download, etc
I'm trying to use .env in teh following way
- read env variables from
.env
- read env variables from
/etc/deductive/...
- Anything in /etc should override the .env file settings
here is my code
const PROD_CONFIG_OVERRIDE_PATH = "/etc/deductive/app-ui-config";
if (!configFileLock) {
configFileLock = true;
if (fs.existsSync(PROD_CONFIG_OVERRIDE_PATH)) {
console.log('AOK ', PROD_CONFIG_OVERRIDE_PATH, 'exists, reading');
console.log(process.env);
const result = dotenv.config({ path: PROD_CONFIG_OVERRIDE_PATH });
console.log(result);
and when I read the values in code later it is with process.env.FOO
To achieve the desired behavior of reading environment variables first from a .env
file and then overriding them with variables from /etc/deductive/...
, you need to ensure that you load both sets of environment variables correctly and in the right order. Here's an approach to implement this:
- Load variables from the
.env
file. - Load variables from
/etc/deductive/...
, which will override any matching variables from the.env
file.
Here’s how you can do it:
const fs = require('fs');
const dotenv = require('dotenv');
const ENV_PATH = '.env';
const PROD_CONFIG_OVERRIDE_PATH = '/etc/deductive/app-ui-config';
// Load environment variables from .env file
dotenv.config({ path: ENV_PATH });
// Check if the production config override path exists and load its variables
if (fs.existsSync(PROD_CONFIG_OVERRIDE_PATH)) {
const result = dotenv.config({ path: PROD_CONFIG_OVERRIDE_PATH });
if (result.error) {
throw result.error;
}
console.log('AOK', PROD_CONFIG_OVERRIDE_PATH, 'exists, reading');
console.log(result.parsed);
}
// Now process.env contains the merged environment variables
console.log(process.env);
// You can now access your environment variables
const foo = process.env.FOO;
console.log(`FOO: ${foo}`);
Explanation
- Load the
.env
file: The firstdotenv.config({ path: ENV_PATH })
loads environment variables from your.env
file and populatesprocess.env
with these variables. - Load the override file: If the file at
PROD_CONFIG_OVERRIDE_PATH
exists, it will be loaded next. Any variables defined in this file will override the corresponding variables already set by the.env
file.
Key Points
- The
fs.existsSync(PROD_CONFIG_OVERRIDE_PATH)
check ensures that the override file exists before attempting to load it. dotenv.config({ path: PROD_CONFIG_OVERRIDE_PATH })
loads the environment variables from the specified path.- If any environment variables are present in both the
.env
file and the override file, the values from the override file will replace those from the.env
file.
This approach ensures that environment variables from /etc/deductive/...
override those from the .env
file, fulfilling your requirements.dotenv itself automatically loads .env
files... so this code you provide doesn't add any gaurentee of ordering, right?
You're correct that dotenv
automatically loads variables from a .env
file by default. To ensure proper ordering and guarantee that environment variables from /etc/deductive/...
override those from the .env
file, you need to explicitly load the .env
file first and then load the override file.
Here’s a refined approach:
- Explicitly load the
.env
file. - Explicitly load the override file if it exists.
const fs = require('fs');
const dotenv = require('dotenv');
const ENV_PATH = '.env';
const PROD_CONFIG_OVERRIDE_PATH = '/etc/deductive/app-ui-config';
// Load environment variables from .env file explicitly
dotenv.config({ path: ENV_PATH });
// Check if the production config override path exists and load its variables
if (fs.existsSync(PROD_CONFIG_OVERRIDE_PATH)) {
const result = dotenv.config({ path: PROD_CONFIG_OVERRIDE_PATH });
if (result.error) {
throw result.error;
}
console.log('AOK', PROD_CONFIG_OVERRIDE_PATH, 'exists, reading');
console.log(result.parsed);
}
// Now process.env contains the merged environment variables
console.log(process.env);
// You can now access your environment variables
const foo = process.env.FOO;
console.log(`FOO: ${foo}`);
Explanation
- Explicitly Load the
.env
File:dotenv.config({ path: ENV_PATH })
ensures that environment variables from the.env
file are loaded first. - Explicitly Load the Override File: If the file at
PROD_CONFIG_OVERRIDE_PATH
exists, it is loaded next withdotenv.config({ path: PROD_CONFIG_OVERRIDE_PATH })
. This ensures that any environment variables defined in the override file will overwrite those from the.env
file.
Important Note
Since dotenv
does automatically load the .env
file if present, it is crucial to call dotenv.config({ path: ENV_PATH })
before checking for and loading the override file. This ensures that the ordering is maintained and the override file has the final say.
This approach guarantees the correct ordering and ensures that environment variables from /etc/deductive/...
override those from the .env
file.But what if dotenv library later loads .env
behind my back?To ensure that you control the loading order of environment variables and prevent dotenv
from loading the .env
file automatically behind your back, you can use dotenv
's override
option introduced in [email protected]
. This option allows you to explicitly control the loading sequence and ensure that the environment variables from the override file take precedence.
Here is the updated code to ensure that the environment variables from /etc/deductive/...
override those from the .env
file:
const fs = require('fs');
const dotenv = require('dotenv');
const ENV_PATH = '.env';
const PROD_CONFIG_OVERRIDE_PATH = '/etc/deductive/app-ui-config';
// Explicitly load environment variables from .env file
dotenv.config({ path: ENV_PATH, override: false });
// Check if the production config override path exists and load its variables
if (fs.existsSync(PROD_CONFIG_OVERRIDE_PATH)) {
const result = dotenv.config({ path: PROD_CONFIG_OVERRIDE_PATH, override: true });
if (result.error) {
throw result.error;
}
console.log('AOK', PROD_CONFIG_OVERRIDE_PATH, 'exists, reading');
console.log(result.parsed);
}
// Now process.env contains the merged environment variables
console.log(process.env);
// You can now access your environment variables
const foo = process.env.FOO;
console.log(`FOO: ${foo}`);
Explanation
- Explicitly Load the
.env
File:dotenv.config({ path: ENV_PATH, override: false })
ensures that environment variables from the.env
file are loaded first. Theoverride: false
option specifies that these variables should not override any existing environment variables. - Explicitly Load the Override File: If the file at
PROD_CONFIG_OVERRIDE_PATH
exists, it is loaded next withdotenv.config({ path: PROD_CONFIG_OVERRIDE_PATH, override: true })
. Theoverride: true
option ensures that any environment variables defined in the override file will overwrite those from the.env
file.
Important Note
The override
option is crucial here to prevent dotenv
from automatically loading the .env
file again and potentially causing conflicts. By setting override
appropriately, you can control the priority of environment variables explicitly.
This approach guarantees that the environment variables from /etc/deductive/...
will override those from the .env
file, maintaining the desired order and ensuring consistency.
Related Chats
Config Environment Variables Override 0.999
Read File as Env 0.657
Update Docker Compose Envvars 0.529
Env File for Docker 0.490
Docker ENV Variables Not Set 0.473
Nohup com env em shell 0.436
Conditional UserProvider Wrapper 0.426
Privacy Page 404 Error 0.395