I'm trying to set a flag that informs my code whether it is in production or development. So far I've seen:
In VS Code's launch.json:
{ "configurations": { "env": "NODE_ENV": "development" } }
In Node's package.json:
{ "scripts": { "start": "NODE_ENV=production" } }
In Webpack's webpack.config.js:
module.exports = { "plugins": new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }) }
While running the code:
set NODE_ENV=production && node app
NPM packages:
https://www.npmjs.com/package/envify
Powershell:
$env:NODE_ENV="production"
I guess I'm just confused because by default I have around 4 of those set currently. How exactly do these interact? Are they all referring to the same variable? Should I only have one of these? Which ones overwrite the others?
I'd really prefer if there were just a single point to set this because it seems like every single module lets you specify it and as a result, I'm confused as to where it is actually being set. Also, is there anyway to access this flag on the client-side as well or is it server-side only?
In the scenario you've specified, the NODE_ENV environment variable will be initialized by the process that is actually executing your code. See the below excerpt from the environment variable wikipedia.
In all Unix and Unix-like systems, each process has its own separate set of environment variables. By default, when a process is created, it inherits a duplicate environment of its parent process, except for explicit changes made by the parent when it creates the child. At the API level, these changes must be done between running fork and exec. Alternatively, from command shells such as bash, a user can change environment variables for a particular command invocation by indirectly invoking it via env or using the ENVIRONMENT_VARIABLE=VALUE <command> notation. All Unix operating system flavors, DOS, and Windows have environment variables; however, they do not all use the same variable names. A running program can access the values of environment variables for configuration purposes.
So if you were to run your code using pm2, then pm2 will actually assign the NODE_ENV environment variable prior to executing your application. It uses a JSON file for options where you can specify your environment variables using the env property.
In short, all the ways to set your NODE_ENV are more or less equivalent, it just boils down to who starts your process.
Since environment variables are local to a machine (the environment) they are set locally and can't be set by a client.
Related
apply-platform
env-bundle
node_modules
node-client
I have a repo apply-platform that has env variables and node modules, in the node module there is another repo node-client.
When I try to access process.env variables inside node-client project I get following object as process.env
{
\"LANG\":\"en_US.UTF-8\",\"PATH\":\"/home/ubuntu/bin:/home/ubuntu/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/snap/bin\",\"HOME\":\"/home/ubuntu\",\"LOGNAME\":\"ubuntu\",\"USER\":\"ubuntu\",\"SHELL\":\"/bin/bash\",\"PM2_USAGE\":\"CLI\",\"PM2_HOME\":\"/home/ubuntu/.pm2\",\"SILENT\":\"true\",\"env_production\":\"[object Object]\",\"instance_var\":\"NODE_APP_INSTANCE\",\"exec_mode\":\"cluster_mode\",\"env\":\"[object Object]\",\"treekill\":\"true\",\"autorestart\":\"true\",\"automation\":\"true\",\"pmx\":\"true\",\"vizion\":\"true\",\"merge_logs\":\"true\",\"cwd\":\"/srv/cbax-apply-platform/\",\"log_type\":\"json\",\"instances\":\"4\",\"name\":\"www\",\"node_args\":\"\",\"pm_exec_path\":\"/srv/cbax-apply-platform/server.js\",\"pm_cwd\":\"/srv/cbax-apply-platform\",\"exec_interpreter\":\"node\",\"pm_out_log_path\":\"/home/ubuntu/.pm2/logs/application.log\",\"pm_err_log_path\":\"/home/ubuntu/.pm2/logs/application.log\",\"pm_pid_path\":\"/home/ubuntu/.pm2/pids/www-13.pid\",\"km_link\":\"false\",\"vizion_running\":\"false\",\"NODE_APP_INSTANCE\":\"0\",\"PM2_JSON_PROCESSING\":\"true\",\"_\":\"/usr/bin/pm2\",\"XDG_DATA_DIRS\":\"/usr/local/share:/usr/share:/var/lib/snapd/desktop\",\"SHLVL\":\"1\",\"PWD\":\"/srv/cbax-apply-platform/\",\"PORT\":\"8080\",\"NODE_ENV\":\"test\",\"REGION\":\"USEastTest\",\"www\":\"{}\",\"status\":\"launching\",\"pm_uptime\":\"1629364026293\",\"axm_actions\":\"\",\"axm_monitor\":\"[object Object]\",\"axm_options\":\"[object Object]\",\"axm_dynamic\":\"[object Object]\",\"created_at\":\"1629364026181\",\"pm_id\":\"13\",\"restart_time\":\"10\",\"unstable_restarts\":\"0\",\"_pm2_version\":\"2.6.1\",\"versioning\":\"null\",\"node_version\":\"9.11.1\",\"exit_code\":\"0\"}
How can I access process.env variables inside the node-module (node-client)
I tried console.log(JSON.stringify(process.env.env)) it still gives me [object][object] as output;
I found this object comes from ecosystem.config.js file of apply-platform , so added these 2 variables and pushed it to the server, but when I console process.env i cant see these 2 variables in node-client
The Node injects the process.env global variable at runtime in our app to use, and it represents the state of the system environment of our app when it starts. So, for example, if the system has the PATH variable set, this will be accessible to you through the process.env.PATH variable you can use to check where binaries are located and make external calls to them if required.
When we write the code, we can never be sure where our app can be deployed. If we require the database in development, we spin up the instance of it, and we link to it via a connection string , something like 127.0.0.1:3306. However, when deploying it to the server in production, we might need to link it to the remote server, 32.22.2.1.
Accessing environment variables in Node.js is supported out of the box. When your Node.js process boots up, it will automatically provide access to all the existing environment variables by creating the env object as a property of the process global object.
Explicitly loading variables from the .env file.
npm install dotenv --save
Afterward, add the following line to the very top of your entry file (index.js or app.js).
require('dotenv').config();
There is a npm module that loads environment variables from .env files into process.env, called dotenv. In your case, you would use it like this:
const dotenv = require("dotenv")
dotenv.config({ path: "/path/to/.env/"})
You could then access the environment variables in Node.js like this:
process.env.MYVAR
If you don't want the variables specified in the .env file to mangle with other environment variables, you can also do this:
const buffer = Buffer.from("PORT=3000") //example
const env = dotenv.parse(buffer) // returns object -> { PORT: 3000 }
// env.PORT would return 3000
dotenv.parse accepts a buffer object and returns an object, instead of binding it to process.env. You could also use the fs module to read the contents of the .env file, and pass it to dotenv.parse.
To learn more, reference the npm page for dotenv: https://www.npmjs.com/package/dotenv
I am using the next-auth library which requires the use of environment variables as follows:
Providers.GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
However, when I test out next-auth it is not working and it seems to me the reason why is because those variables are not loading properly. As such, I did a little test to see if I can access environment variables in my app and the test showed that I cannot.
This is how the test went:
// .env.local (root level)
NEXT_PUBLIC_ENV_LOCAL_VARIABLE="public_variable_from_env_local"
I then add the following code to my site:
<h2>test one start</h2>
{process.env.NEXT_PUBLIC_TEST_ONE}
<h2>test one end</h2>
<Spacer />
<h2>test two start</h2>
{process.env.TEST_TWO}
<h2>test two end</h2>
In this case, test one start shows up and test one end shows up, but the environmental variable does NOT show up. The same is true for test two start and test two end.
I did a similar test with console.log - namely:
console.log("test one", process.env.NEXT_PUBLIC_TEST_ONE)
console.log("test two", process.env.TEST_TWO)
That turns up as follows:
test one undefined
test two undefined
In short, for whatever reason I seem unable to load environment variables in my nextjs app. Not from next-auth, not in the code and not in a console.log. The variables are undefined and I do not know why.
Any ideas?
Thanks.
.env.* files are loaded when server starts. Hence, any modification in them is not applied unless you restart your dev/prod server.
Just halt the process (Ctrl+C/Z) and re-run next dev/next start to make them work. Note that you may also need to re-build the project (next build) before starting in production mode if you are using them in pages that are statically generated.
To be clear, according to the most recent docs, you are supposed to
place the variables in an .env.local file
then config your next.config.js file so it includes an env config
referencing your variables like this:
module.exports = {
env: {
secretKey: process.env.your_secret_here,
},
}
then you can call the variables on the client-side using the typical process.env.secret_here syntax. I may be mistaken but I do believe the NEXT_PUBLIC prefix exposes the env variables to the client-side and should ONLY be done in a dev environment to avoid security issues.
Searching the next.js documentation I found this:
// file: next.config.js
module.exports = {
env: {
customKey: 'my-value',
},
}
// Now you can access process.env.customKey
// For example, the following line:
// return <h1>The value of customKey is: {process.env.customKey}</h1>
// Will end up being:
// return <h1>The value of customKey is: {'my-value'}</h1>
So it seems, if you are using next.js version at or before 9.4 you place env variables into next.config.js
They also include one warning:
Next.js will replace process.env.customKey with 'my-value' at build time. Trying to destructure process.env variables won't work due to the nature of webpack DefinePlugin.
If you are using version 9.4+ the documentation says you can use .env.local files and prefix env variables with NEXT_PUBLIC_ to have them exposed in the browser.
Of note with this method is: In order to keep server-only secrets safe, Next.js replaces process.env.* with the correct values at build time. This means that process.env is not a standard JavaScript object, so you’re not able to use object destructuring.
In my CRA app, util JS file, there is a method pause which I would like to change depending on the environment it's running.
class CompilationEngine {
...
pause () {
return new Promise(resolve => emitter.once('next', resolve))
}
...
}
I want pause function to return Promise.resolve() in test environment(when I run npm run start) since some tests are failing due to next event not emitted in console test. So how can I
detect the environment and change the code inside pause function.
I think you're looking for
process.env.NODE_ENV
right?
Quickly answer
In CRA you can use environment variables declaring them before the npm run start
You must create custom environment variables beginning with REACT_APP_. Example:
export REACT_APP_DISABLE_NEXT = true
CRA framework will expose this operative system level variable to a simple javascript variable ready to use in any part of your react code:
process.env.REACT_APP_NOT_SECRET_CODE
source:
https://create-react-app.dev/docs/adding-custom-environment-variables/
Explanation
Environment variables like export FOO=BAR are variables at operative system level. These variables are easy accessed with:
process.env.FOO
React is not a nodejs javascript. React will be converted to vanilla javascript to be able to run in a browser. In this javascript process.env does not exist.
But CRA Framework (which is nodejs), have access to the operative system variables, so it create us an emulation of process.env containing just variables which start with REACT_APP_. Any other variable without REACT_APP_, will be ignored
Advice
Expose export REACT_APP_DISABLE_NEXT = true just in dev or test stage, not in prod
I am using environment variables in my code as explained in the vue-cli-service environment variables section, and it surely works when the environment variables are defined.
But when one of the environment variables is undefined, it just replaces it with undefined.
Let's say if I introduce a new process.env.VUE_APP_MY_NEW_VAR, but then I don't set it in the environment, it will just put an undefined there.
I wanted to be sure that when building the project (npx vue-cli-service build [...]), none of the environment variables remain undefined.
One of my ideas is to check for undefined always, but it would happen at run time, not compile time.
Another idea is to create a shell script to check that all the variables are set before building, but that sounds quite manual.
Is there a way to do configure it and make it part of the build?
You can add a check in vue.config.js. For example
const REQUIRED_ENV_VARS = [
'VUE_APP_VAR_1',
'VUE_APP_VAR_2'
]
if (REQUIRED_ENV_VARS.some(env => typeof process.env[env] === 'undefined')) {
throw new Error('Required environment variables are missing')
}
Right now, whenever I want to deploy a node.js server to my production server, I need to change all the IP/DNS/username/password for my various connection to my databases and external APIs.
This process is annoying, is there a way to verify if the currently running node.js instance is in cloud9ide or actually my production joyent smartmachine?
If I am able to detemrine (in my running code) on which server my node.js instance is running , I'll add a condition that set the values to the prod or dev.
Thank you
Normally you should run a node app in production like this:
NODE_ENV=production node app.js
Applications with Express, Socket.IO and other use process.env.NODE_ENV to figure out the environment.
In development you can omit that and just run the app normally with node app.js.
You can detect the environment in your code like this:
var env = process.env.NODE_ENV || 'development';
loadConfigFile(env + '.json', doStuff);
Resources:
How do you detect the environment in an express.js app?
I think the easiest way to set the environment is to pass command-line argument to your application.
node ./server.js dev
In your script you need to handle this argument and set configuration what you need for it.
var env = process.argv[2] || 'dev';
switch (env) {
case 'dev':
// Setup development config
break;
case 'prod':
// Setup production config
break;
}
Also, i was created module that makes the configuration process a bit easier. Maybe it will help you.
Actually, I would not recommend to store configuration values like database connection information, passwords, access tokens and such inside of actual application code for the following reasons:
Hardcoding those values make it difficult to change them later on. You will have to release a new version of the application to change those values.
This is a serious security violation, because production-grade configuration data and passwords shouldn't be stored in code. It's very easy to leak this sensitive data.
The better approach would be to externalize this data and pass it to your application during execution. This is normally done by means of environment variables. You just need to define unique environment variable for each peace of data that needs to be changeable between different environments.
For example: DB_HOST, DB_USER, DB_PASSWORD. Then you could pass those values to you app in production this way:
$ NODE_ENV=production DB_HOST=1.2.3.4 DB_USER=someusername DB_PASSWORD=somerandompassword /bin/node app.js
Actually, this values could be encrypted and added to the codebase and then decrypted during the deployment. However, make sure that decryption key is stored securely in deployment system or provided interactively by the release engineer. Shippable allows to do this out of the box.
In the development environment it gets simpler, because you can use very convenient dotenv module. Just create a .env file in your project's root directory and add all variables to it:
DB_HOST=1.2.3.4
DB_USER=someusername
DB_PASSWORD=somerandompassword
But, make sure to exclude it from you VCS, because each developer probably would want to have personal configuration. You can create a .env.dist file to contain default configuration, which later could be used as a template: cp .env.dist .env.
For that you can just check it out with the help of environment variables and you can perform any actions.
if (process.env.NODE_ENV === "production") {
//do something in production
}
if (process.env.NODE_ENV !== "production") {
//do something in development
}