Skip to content

v1 Dotenv

Jonathan Sharpe edited this page Aug 24, 2024 · 1 revision

dotenv is a common way to manage environment variables in your local environment. It is preinstalled in the starter kit, and loaded for the server files in server/utils/config.js. To use it, create a file named .env in the root directory. This file will contain the extra environment variables that you want dotenv to load, for example:

DATABASE_URL=postgres://postgres:opensesame@localhost:5432/cyf  # see https://github.com/textbook/starter-kit/wiki/Dev-setup#databases
LOG_LEVEL=debug

If needed, you can add properties to the object exported from server/utils/config.js for your other server files to use.

⚠️ Note process.env.<THING> should appear only in server/utils/config.js, to make it clear what configuration is coming from the environment. Any other parts of your app that need configuration can then import it from that single place.

Client environment variables

If you're coming from Create React App and have got used to the custom environment variables feature, you can do this yourself with Webpack's DefinePlugin. Note that per my blog post, however, I would generally recommend run time rather than build time configuration wherever possible.

To load the environment variables into your client code, make the following changes to ./client/webpack/common.config.js:

const HtmlWebpackPlugin = require("html-webpack-plugin");

// add these two requires
const { DefinePlugin } = require("webpack");
require("dotenv").config();

module.exports = {
	...,
	plugins: [
		new HtmlWebpackPlugin({ ... }),
                // add this plugin with any env vars you want to define
		new DefinePlugin({
			// "process.env.<NAME_IN_APP>": JSON.stringify(process.env.<DOTENV_FILE_NAME>),
                        "process.env.APP_VERSION": JSON.stringify(process.env.APP_VERSION),
                        ...,
		}),
	],
};

⚠️ Note that this is simple text substitution, only the literal text process.env.APP_VERSION gets replaced with the value. If you had e.g. const envVars = process.env then envVars.APP_VERSION, that wouldn't work. See e.g. https://stackoverflow.com/a/76440819/3001761.

You can still use the REACT_APP_ (or another prefix) convention if you want to, and if you want a more automated loading of some set of environment variables you could borrow from CRA's implementation, e.g.:

const prefix = "REACT_APP_";

const varsToDefine = Object
	.entries(process.env)
	.filter(([key]) => key.startsWith(prefix))
        .reduce((env, [key, value]) => ({
                ...env,
		[`process.env.${key.slice(prefix.length)}`]: JSON.stringify(value),
	}), {});

Now any env var prefixed with REACT_APP_ in your dotenv file (e.g. REACT_APP_CLIENT_KEY=123) will be available in your client code without that prefix (e.g. process.env.CLIENT_KEY). You can tweak this recipe as needed.

⚠️ Note if you do the automatic loading you must use a prefix to distinguish the env vars that should be part of the client build from everything else available in the build environment. Otherwise you can end up leaking credentials (embarrassing example of this from ABC).

In production

Note that the .env file is only for local development. You'll also need to set those environment variables wherever you're building the app for production, e.g. in the standard setup:

Clone this wiki locally