Can't access process.env values using dynamic keys
I have a nextjs (not sure if it has any relevance or does it apply to nodejs as a whole) project in which I would like to access a value from process.env
using a dynamic key:
const myKey = 'MY_KEY'
console.log(process.env[myKey]) //undefined
For reference, I have tried:
console.log(process.env['MY_KEY']) // gives value under MY_KEY
console.log(process.env.MY_KEY) // works too
Solution 1:
First of all, one thing to note, that if you want to use env
variables on the client then you need to prefix them with NEXT_PUBLIC_
, or use older way of exposing them to the client inside next.config.js
.
As for the question, this is due to nature of how Webpack DefinePlugin works which I believe NextJs uses internally. It does direct text replacement at build time, in simpler words it just looks for process.env.MY_KEY
string and replaces it with value. But if you destructure it then plugin just can't find process.env.MY_KEY
string anymore and you are getting nothing (process.env
object is generated anyway, but it will be empty).
Although this only true for client side code, because for server side Next actually uses real process.env
object and destructuring will work there.
For example, if we have NEXT_PUBLIC_MY_KEY=somevalue
and we log this somewhere in the code:
const key = 'NEXT_PUBLIC_MY_KEY';
console.log(process.env.NEXT_PUBLIC_MY_KEY);
console.log(process.env['NEXT_PUBLIC_MY_KEY']);
console.log(process.env[key]);
console.log(process.env);
On client side you will get:
somevalue
somevalue
undefined
{} // empty object
And on server side you will get:
somevalue
somevalue
somevalue
{ ... } // object with all available env values, even system ones
There is a little bit of info about it in older env docs.
Workaround
You could probably use Runtime Configuration, but it has it's own limitations, for example, I think the page should be dynamic (should use getInitialProps
or getServerSideProps
) to work.
// next.config.js
module.exports = {
publicRuntimeConfig: {
myEnv: 'somevalue',
// or actually use process.env variables, they are all available here
myEnv2: process.env.MY_ENV
},
};
import getConfig from 'next/config';
const key = 'myEnv';
getConfig().publicRuntimeConfig[key] // 'somevalue'
Or just pass your variables through getServerSideProps
like the other answer mentioned.
EDIT:
I've actually just tested publicRuntimeConfig
and it works even on static pages, at least if you are using next start
. Not sure why docs says that the page should have getServerSideProps
. So this might be the solution in the end.
Solution 2:
As someone else has already correctly mentioned, this problem occurs because that's how the Webpack DefinePlugin works.
Solution
Extending the webpack config. You can filter out all environment variables, starting with NEXT_PUBLIC_
and add them with the DefinePlugin webpack plugin to the process.env
object. This way you can call them dynamically in the browser.
next.config.js
module.exports = {
webpack: (config, { webpack, isServer }) => {
const envs = {};
Object.keys(process.env).forEach(env => {
if (env.startsWith('NEXT_PUBLIC_')) {
envs[env] = process.env[env];
}
})
if (!isServer) {
config.plugins.push(new webpack.DefinePlugin({
'process.env': JSON.stringify(envs),
}))
}
return config
},
}
your page
import { useEffect } from 'react';
const keys = ['FOO', 'NEXT_PUBLIC_FOO'];
export default function Home() {
useEffect(() => {
keys.forEach(key => console.log(process.env[key]));
}, []);
return (
<>
</>
)
}
Workaround
This workaround adds all environment variables prefixed with NEXT_PUBLIC
to become dynamically available in the frontend.
import { useEffect } from 'react';
const keys = ['FOO', 'NEXT_PUBLIC_FOO'];
export default function Home(props) {
useEffect(() => {
keys.forEach(key => console.log(props.envs[key]));
}, []);
return (
<>
</>
)
}
export async function getStaticProps() {
const envs = {};
Object.keys(process.env).forEach(env => {
if (env.startsWith('NEXT_PUBLIC_')) {
envs[env] = process.env[env];
}
})
return {
props: {
envs,
},
}
}
The important part is, that you use the getStaticProps
method. Here you filter out all environment variables starting with NEXT_PUBLIC_
and add them to the envs property. This allows them to be dynamically usable in the frontend.
In this example, the value of NEXT_PUBLIC_FOO
will log to the console, while the value of FOO
is undefined
.