How to load custom process environment .ENV variables in webpack with craco (Create React App Configuration Override)

Alex OkrosAlex Okros
2 min read

When you're using craco, and you need to specify different .env files with different .env variables, you'll need to override some webpack configs.

We'll be using 4 .env files:

.env.local
.env.development
.env.staging
.env.production

We'll then open craco.config.js from our project root and add the following:

const DotEnv = require('dotenv');
const webpack = require('webpack');


const ENV = process.env.DEPLOY_ENV || 'dev';
const result = DotEnv.config({ path: `./.env.${ENV}` });

if (result.error) {
  throw result.error;
}

const env = DotEnv.config({ path: `./.env.${ENV}` }).parsed;
const envLocal = DotEnv.config({ path: './.env.local' }).parsed || {};

// collect all .env keys and values
const envKeys = Object.keys(env).reduce((prev, next) => {
  // first we search for each key inside of .env.local, because of precedence
  prev[`process.env.${next.trim()}`] = (envLocal[next]) ? JSON.stringify(envLocal[next].trim()) : JSON.stringify(env[next].trim());

  return prev;
}, {});

// check things out
console.log(`
  key: ${ENV.toLocaleUpperCase()},
  value: ${process.env.REACT_APP_DEPLOY_ENV},
  accumulator: ${envKeys}
`);

// feed them keys to your brand new custom webpack configuration
module.exports = {
  webpack: {
    plugins: [
      new webpack.DefinePlugin(envKeys),
    ],
  },
};

To break things up:

Install dotenv npm packages if you haven't already:

npm install dotenv --save-dev

Open craco.config.js and import dotenv and webpack packages:

const DotEnv = require('dotenv');
const webpack = require('webpack');

Add a REACT_APP_DEPLOY_ENV (or however you want to call it) variable in all your .env files:

REACT_APP_DEPLOY_ENV='local' // this is for .env.local
REACT_APP_DEPLOY_ENV='dev' // this is for .env.development
REACT_APP_DEPLOY_ENV='stg' // this is for .env.staging
REACT_APP_DEPLOY_ENV='prd' // this is for .env.production

Load up your REACT_APP_DEPLOY_ENV and check for the .env file depending on the dev medium you're on, with the help of the dotenv package:

// load .env files based on your present medium you're on
const ENV = process.env.DEPLOY_ENV || 'dev';
const result = DotEnv.config({ path: `./.env.${ENV}` });

// if there's no file, throw an error
if (result.error) {
  throw result.error;
}

Load up your .env and .env.local (this should have precedence because different developers work on different files) in JSON format:

const env = DotEnv.config({ path: `./.env.${ENV}` }).parsed;
const envLocal = DotEnv.config({ path: './.env.local' }).parsed || {};

Accumulate all those keys with the help of a reducer:

const envKeys = Object.keys(env).reduce((prev, next) => {
  // .env.local variables have priority over other .env files
  prev[`process.env.${next.trim()}`] = (envLocal[next]) ? JSON.stringify(envLocal[next].trim()) : JSON.stringify(env[next].trim());

  return prev;
}, {});

And finally feed them to the webpack configuration:

module.exports = {
  eslint: {
    enable: true,
  },
  webpack: {
    plugins: [
      new webpack.DefinePlugin(envKeys),
    ],
  },
};

Just make sure, before you commit and push, to:

  1. Delete .env.local OR

  2. add .env.local to your .gitignore file

And that's it.

Skol!

Cover image credit: https://www.doppler.com/

4
Subscribe to my newsletter

Read articles from Alex Okros directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Alex Okros
Alex Okros