When using Next.js to create web application, we can use environment variable files like .env.development and .env.production. And fill it with env variables like below;
NEXT_PUBLIC_API_ENDPOINT="https://some.api.url/api"
And my question is "When are these variables used?"
When I build next.js application with next build, it prompts:
> next build
info - Loaded env from ~/project/folder/.env.production
info - Loaded env from ~/project/folder/.env
And When I serve build result with next start :
> next start
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info - Loaded env from ~/project/folder/.env.production
info - Loaded env from ~/project/folder/.env
So this means env is loaded on build-time, and run-time.
But there must be one time where ENV variables are loaded and used.
When is these variables defined in the env file are used?
Because there may be access to these variables both at build-time AND at runtime.
For example:
Your build will use them to create built outputs, like static code
At runtime your code may require in-process access to them, like for handling server-side requests
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.
I build a web app using react, webpack, docker and AWS.
I create a feature which depends on environment variable. So if the environment variable value is true, the feature will be showing on the frontend.
The problem is, when I changed the environment variable on the server (Webpack already done building the app, the app is already deployed and running), my feature is not showing. I guess due to the app cannot read the value changes on system environment variable.
How can I achieve this ? is it possible to do it ?
=====
I use dotenv webpack for managing my environment variables. I already set the systemvars to true to detect all environment variables from the system or .env file.
=====
So why am I doing this, because I dont want to make a Pull Request to push a new value for environment variables. I just want to reserve the environment variables name, and change the value directly from the server if the feature is ready to deployed. And if there is an error, I just need to change the environment variable to something and the feature is down.
You simply cant change environment variable. Evn variables loaded on compile/webpack load time. So once app start u cant change, process.env.
Solution as #jonrsharpe explains. You need to create, some sort of database. It could be memory or file or database. You read data from that. Expose a API, to update the data base.
Express sample:
global.enableFeature = false
app.post("/updateFeatureToggle", (req, res) => {
const enableFeature = req.body.enableFeature
global.enableFeature = enableFeature
res.send({success: "OK"})
})
In another file, read from global.enableFeature. This is in memory-based.
I have a react component which in development will redirect to a localhost url but in production to a different url. In my backend I have the same situation and there i solved it with a package called dotenv. I was wondering how someone would do this in a react front-end.
export default withRouter(function Login(props) {
useEffect(() => {
if(localStorage.getItem('jwt')){
props.history.push('/dashboard');
}
})
const handleLogin = () => {
window.location.href = "http://localhost:8000/auth/google";
}
return (
<LoginView handleLogin={handleLogin}/>
)
})
You can use dotenv to add environment variables to react as well. During app deployment(in the build process) the environment variables must be replaced with the corresponding URLs (as this is the most frequently encountered use case in front-end applications). This can be done while configuring the build process.
Here is an example using Webpack https://medium.com/#trekinbami/using-environment-variables-in-react-6b0a99d83cf5
The whole idea here is to create a file (called just .env) filled with
your environment variables. To prevent people from finding out your
local database password is the same one you use for every single one
of your accounts on the internet , I urge you to add the .env file to
your .gitignore. Your front-end code will refer to the same
environment variable (process.env.API_URL) on both environments
(development/production), but because you defined different values in
your .env files, the compiled values will be different.
I would suggest having a separate .env file for the react app as it should not be accidentally served with the website.
Create React App has a module(built around the node dotenv module) you can use for adding custom environment variables
https://create-react-app.dev/docs/adding-custom-environment-variables/
The environment variables are embedded during the build time. Since
Create React App produces a static HTML/CSS/JS bundle, it can’t
possibly read them at runtime. To read them at runtime, you would need
to load HTML into memory on the server and replace placeholders in
runtime, as described here. Alternatively you can rebuild the app on
the server anytime you change them.
Its depend on how you are using react.
If you are using react-script, you can go will above solution(https://create-react-app.dev/docs/adding-custom-environment-variables/).
But if you are using webpack, try to use DotenvPlugin in place of dotenv module (https://webpack.js.org/plugins/environment-plugin/).
In my opinion, pls don't follow method 1 use in medium link, as env should not be push on git but package.json need to be done.
I am currently making a Meteor app and am having trouble reading files from the private subdirectory. I have been following a couple different tutorials and managed to get it to work flawlessly when I run the meteor app locally. This question (Find absolute base path of the project directory) helped me come up with using process.env.PWD to access the root directory, and from there I use .join() to access the private folder and the pertinent file inside. However, when I deployed this code, the website crashes on startup. I am very confident that it is an issue with process.env.PWD, so I am wondering what the proper method of getting Meteor's root directory on a deployed app is.
//code to run on server at startup
var path = Npm.require('path')
//I also tried using the below line (which was recommended in another Stackoverflow question) to no avail
//var meteor_root = Npm.require('fs').realpathSync( process.cwd() + '/../' );
var apnagent = Meteor.require("apnagent"),
agent = new apnagent.Agent();
agent.set('cert file', path.join(process.env.PWD, "private", "certificate-file.pem"))
agent.set('key file', path.join(process.env.PWD, "private", "devkey-file.pem"))
In development mode the file structure is different than after bundling, so you should never rely on it. Particularly, you should not access your files directly like you're doing with path methods.
Loading private assets is described in this section of Meteor's documentation. It mostly boils down to this method:
Assets.getBinary("certificate-file.pem");
and it's getText counterpart.
As for configuring APN agent, see this section of documentation. You don't have to configure the agent by passing file path as cert file param. Instead you may pass the raw data returned by Assets methods directly as cert. The same holds for key file ~ key pair and other settings.
As an alternative, you would need to submit your files independently to the production server to a different folder than your Meteor app and use their global path. This, however, would not be possible for cloud providers like Heroku, so it's better to use assets in the intended way.