[Support Guide] Using environment variables on Netlify correctly

Last reviewed: August 2023

The preferred way to use environment variables in Netlify is to set them in our environment - be that in the Environment Variables settings UI (on the site’s “Build & Deploy settings” page), or via netlify.toml. You’ll want to choose the right pattern to meet your needs. Setting variables in our UI may be considered a bit more secure, since only people with access to the Netlify admin UI for your site can see them, rather than “anyone who can clone your repo!”.

These variables are made available primarily in the build environment - if your build command were env, then you’d see them listed - in addition to $PATH and $NODE_VERSION and some other stuff Netlify sets automatically. However, depending on how your build pipeline works, the variables may or may not be available once your build command starts. If your build command is node -p "process.env" - that will show you what Node.js sees for environment variables - and that should show the same thing as env shows (which is what the shell run by the build container sees). This generally works correctly automatically and you don’t have to do those experiments to prove that the variables were or weren’t set unless you are debugging new settings in netlify.toml.

However, some of the build pipelines that folks use DON’T automatically import/inherit variables from the parent shells. This thread shows such an example. So - the best practice is not to necessarily use something like dotenv but instead, use a build process that appropriately passes those environment variables that we expose in the shell, into the build environment. How you do that is up to you and your tools.

So, now you have the variables set and available to your build process, great! But, unless your build pipeline DOES something with the environment variable - it’s not going to be much use in the code that gets published and served to the browser - which doesn’t understand $API_ENDPOINT - that’s just a string to the browser and to our CDN. Only the build environment knows about and can use environment variables in most cases, since they are set in the shell during build. But your code is not served from the build environment - it is served without modification after build. As a very small example workflow, we could “pass on” the $CONTEXT variable into a file that you can access at browse time, like this, during build:

npm run build && echo $CONTEXT > public/netlify-context.txt

There are some specific other use cases that enable environment variables for use directly at browse time, such as:

  1. Gatsby environment variables
  2. React environment variables
  3. Vue environment variables
  4. Next.js environment variables

You can also check a full list of environment variables recognized and set by Netlify, here.

3 Likes

But how do we acutally used those evnironment variables inside the site.

7 Likes

Hi @mittalyashu.

It seems like you’re asking about how to leverage environment variables throughout your source code, since I assume you read the above post, and understand that:

Only the build environment knows about and can use environment variables in most cases, since they are set in the shell during build, but your code is not served from the build environment - it is served without modification after build.

dotenv (linked above) is a popular npm module that allows you to leverage environment variables in a project. It allows you to set secret variables and reference them in public code elsewhere, like connecting to a database for example:

# .env file in project root

DB_HOST=localhost
DB_USER=user
DB_PASS=password
// server.js file

require('dotenv').config()
const db = require('db')

db.connect({
  host: process.env.DB_HOST,
  username: process.env.DB_USER,
  password: process.env.DB_PASS
})

Yes, I am aware of that dotenv package.

But in order to use that package we have to define the .env file in the repository to use the defined variables, which means if the repository source code is public, then anyone can have access to the environment variables.

I answered using .env on Netlify to be able to use dotenv on your build on SO, but here is the cross post:

WARNING: If this is a secret key, you will not want to expose this environment variable value in any bundle that gets returned to the client. It should only be used by your build scripts to be used to create your content during build.

Issue

dotenv-webpack expects there to be a .env file to load in your variables during the webpack build of your bundle. When the repository is checked out by Netlify, the .env does not exist because for good reason it is in .gitignore.

Solution

Store your API_KEY in the Netlify build environment variables and build the .env using a script prior to running the build command.

scripts/create-env.js

const fs = require('fs')
fs.writeFileSync('./.env', `API_KEY=${process.env.API_KEY}\n`)

Run the script as part of your build

node ./scripts/create-env.js && <your_existing_webpack_build_command>

Caveats & Recommendations

  • Do not use this method with a public facing repository if you are trying to hide the keys [open] because any PR or branch deploy could create a simple script into your code to expose the API_KEY
  • Only use the private keys for your build env. Public environment variables are safe to access inside your client code bundles.
  • The example script above is for simplicity so, make any script you use be able to error out with a code other than 0 so if the script fails the deploy will fail.
7 Likes

Hello mittalyashu. Your repo may be public but the way to get around having it exposed to your remote repository (if you’re using git) is to include the .env file in your .gitignore file. Assuming that your .env file is in your head director you would simply type the filepath relative to your head repository to where the .env file is. For me this looked like:

(assume we’re in .gitignore)

.env

1 Like

wrote up an introductory post on env vars in case this helps anyone DigitalOcean Community | DigitalOcean

@christiancw, does that edit mean that you solved the issue?

Edit: needed to add dotenv to my webpack plugins.

Not quite. I had thought so, since it worked when I ran netlify dev but then the keys still are not being passed to my React component when I deploy the site - though I can tell they are accessible at build time. With the keys stored on the Netlify UI, and with a create-env script, is there any other reasons the keys wouldn’t be available on process.env in the React component?

Sharing what worked for me, for a Netlify lambda function:

  1. Adding environment variables through Netlify’s UI widget (on the site’s “Build & Deploy settings” page).

  2. netlify.toml

[build]
    Command = "npm run lambda-build"
    Functions = "lambda"
  1. Adding node -p 'process.env' to my package.json lamba-build command:

"lambda-build": "netlify-lambda build functions && node -p 'process.env'"

This way, when the function is deployed, env variables will we loaded and available to the function.

2 Likes

Hey!! I tried this and the script runs fine, it seems. But, I can still only access env vars defined manually in my dashboard. I’m trying to access the COMMIT_REF, NODE_ENV, etc. for inside my zip-it-and-ship-it functions.

I have this:

fs.writeFileSync(
  './.env',
  `NODE_ENV=${process.env.NODE_ENV}\nCOMMIT_REF=${process.env.COMMIT_REF}\nCONTEXT=${process.env.CONTEXT}\nTESTY='TESTYyyyyy'\n`,
);

But, everything is still undefined, except when I tested NODE_ENV by adding NODE_ENV=development to the dashboard env vars.

Any thoughts?

Only environment variables in the dashboard are available at the time of a function execution in Netlify Functions at the time of this answer. :yum:

Ah, ok. So there’s no possibly way to expose COMMIT_REF or even NODE_ENV in functions? Seems like some crucial environment functionality, right? Maybe I’m missing something.

For now, I’m checking to see if NETLIFY_DEV exists, and if it does not, then I’m assuming I’m in production. Not my favorite, though. haha

NODE_ENV should be there. Not sure where COMMIT_REF is setup.

Hmm NODE_ENV is undefined. I don’t use netlify-lambda or anything; just the built-in zip-it-and-ship-it.

Weird. Hopefully someone can shed some light on this!

A post was split to a new topic: API keys and environment variables on netlify

Hi @bswank,

During the netlify build process you can both modify your function and access en vars, which means you can use a custom webpack plugin, script, etc. to hardcode the environment variables you need in to the functions the same way React automatically hardcodes en vars that start with REACT_APP_ in to the client side javascript. You’ll have to do it yourself but it’s definitely possible.

thanks futuregerald. If I’ve create an environment variable (GAME_ID) in settings ( Netlify App) , then how do I access that variable in my webpack.config.js? Specifically I want to use the environment variable in the entry property:

module.exports = (env = {}) => {

console.log(“env $$$$$$$”, env);
console.log(“process.env $$$$$$$”, process.env);
console.log(“GAME_ID”, GAME_ID)

return {
entry: env.production ? /* ./src/games/${env.GAME_ID}.js */ ‘./src/boilerplate/game.ts’ : ‘./src/boilerplate/game.ts’, // ‘./src/games/asteroid/game.ts’,

There are probably a million ways, but when I need to populate a file with a value, I do something like this in my build command:

sed -i s/PLACEHOLDER/${VARIABLENAME}/g webpack.js && my-usual-build-command

This way the value is put in place in the file before I need it. I don’t know how webpack runs things in its config file while you use it, so there may be a more elegant way but it comes back down to “populate the value in a file before you need it”.

thanks greatly for your help

I have added the snippet to my build command in my package.json:

“scripts”: {
“build”: “sed -i s/PLACEHOLDER/${GAME_ID}/g webpack.config.js && webpack --mode=production --env.production”

and the build & deploy run successfully. But my webpack.config.js still cannot see the variable:

6:22:59 PM: > sed -i s/PLACEHOLDER/${GAME_ID}/g webpack.config.js && webpack --mode=production --env.production
6:22:59 PM: env $$$$$$$ { production: true }
6:22:59 PM: env.GAME_ID $$$$$$$ undefined

the webpack site has a page about environment variables:

it shows that if I define module.exports with a function that takes an env argument then I will have access to the env variable inside the body of the function.

So I do this in my webpack.config.js but there is no sign of my GAME_ID environment variable value:

module.exports = env => {

console.log(“env $$$$$$$”, env);
console.log(“env.GAME_ID $$$$$$$”, env.GAME_ID);