Manage Configuration Values with Environment Variables

Mark Shust
InstructorMark Shust

Share this video with your friends

Send Tweet
Published 5 years ago
Updated 3 years ago

Storing configuration in files instead of the environment has many downsides, including mistakenly checking in the wrong configuration in the wrong environment, coupling configuration with code, and scaling issues in larger server architectures.

We’ll learn how to update app code to look at environment variables for configuration values instead of using configuration files, and different approaches for managing environment variables between dev/stage/prod.

Instructor: [00:00] Let's create a new project named Foo. In there, let's create a simple Node.js script that connects to a locally running MongoDB instance. We'll install the MongoDB module with Yarn, and then start our script with Node. We can see that we can successfully connect to our MongoDB instance.

[00:22] The current configuration doesn't allow for the connection string to be changed on the fly. Moving configuration values into environment variables has many benefits. Let's go ahead and copy the connection string, and replace it with a reference to our environment variable.

[00:38] Environment variables are referenced by process.env, followed by the name of our environment variable in caps. In this case, we'll name it Mongo_URI. Let's save our file. We'll start the Node script again, but this time prepend the command with our new environment variable.

[00:59] We can see that we can still connect to the database, but our connection string is moved out of code and into the environment. If you have many environment variables or want an easier way to start your script, you can create a new .env file and move your environment variables there.

[01:17] To inject our external environment file into our Node.js script, we'll need a package called .env. Let's add it with Yarn. Next, we'll require this module at the top of our script, immediately invoking the config function. This function will automatically look for a file named .env, and inject the values contained within this file into the environment.

[01:43] Let's go back and start our Node process directly now, and see that we are still connecting to the MongoDB instance from the values within our environment file.

Chetan Kantharia
Chetan Kantharia
~ 4 years ago

Is it a good practice to add .env file to a repo, because it may leak credential if the project is open-source.

Michael
Michael
~ 4 years ago
Michael
Michael
~ 4 years ago

Is the .env file not a configuration file? Even if the configuration data is stored in process.env, it is still passed as a file that has to be parsed in the used language. All the disadvantages mentioned apply IMO:

mistakenly checking in the wrong configuration in the wrong environment, coupling configuration with code, and scaling issues in larger server architectures

Mark Shust
Mark Shustinstructor
~ 4 years ago

environment variables, whether passed by file or set within the environment, i'd consider runtime config. there needs to be a way between dev/stage/prod/whatever to use the same config files but still change specific values of the config on the fly. if things require a higher-level of security, secrets should be used.

fyi there are also situations that aren't present within this tut, such as running swarm or kubernetes. say an api key is set from an env var, and it needs to be immediately changed on my cluster of nodes. i can issue an env var update on the fly without rebuilding my entire artifact/build, and it's immediately updated.

Rajat S
Rajat S
~ 4 years ago

Cannot connect to MongoDB! { MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017] at Pool.<anonymous> (/Users/sahusoft/twelve-factor/foo/node_modules/mongodb-core/lib/topologies/server.js:503:11) at Pool.emit (events.js:127:13) at Connection.<anonymous> (/Users/sahusoft/twelve-factor/foo/node_modules/mongodb-core/lib/connection/pool.js:326:12) at Object.onceWrapper (events.js:219:13) at Connection.emit (events.js:127:13) at Socket.<anonymous> (/Users/sahusoft/twelve-factor/foo/node_modules/mongodb-core/lib/connection/connection.js:245:50) at Object.onceWrapper (events.js:219:13) at Socket.emit (events.js:127:13) at emitErrorNT (internal/streams/destroy.js:64:8) at process._tickCallback (internal/process/next_tick.js:152:19) name: 'MongoNetworkError', message: 'failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017]' }

Michael
Michael
~ 4 years ago

@Rajat Have you startet a MongoDB instance? It is not shown in the video.

Hoang
Hoang
~ 3 years ago

Yeah I was facing the same problem,

$ brew install mongodb

$ brew services start mongodb

Mark Shust
Mark Shustinstructor
~ 3 years ago

@Rajat Have you startet a MongoDB instance? It is not shown in the video.

Correct, the video assumes you have a locally running mongodb instance.

Mark Shust
Mark Shustinstructor
~ 3 years ago

Is it a good practice to add .env file to a repo, because it may leak credential if the project is open-source.

No, you don't want to necessarily add this file to your repo unless the environment variables do not need to be secure.

Mark Shust
Mark Shustinstructor
~ 3 years ago

What about security (see Environment Variables Considered Harmful for Your Secrets)?

This course follows methodologies of the 12-Factor app, and does not necessarily contain opinions on what is considered secure or insecure. Storing credentials within environment variables aren't any less secure than storing them within application files. That said, there could be other methods (such as docker secrets) which are considered more secure depending on your application needs.

These black/white discussions needs to stop as there are many ways do to things, and one way isn't necessarily any more better or worse than all other ways. New methods and techniques are always created, and that doesn't necessarily mean that every single previous approach is no longer "correct". You need to look at your specific application and determine what is appropriate for your own needs.

josh
josh
~ 3 years ago

It's unfortunate you felt the need to demonstrate this concept using mongodb (or any other database). It distracts from the concept and it assumes prior experience with the database in question

Mark Shust
Mark Shustinstructor
~ 3 years ago

It's unfortunate you felt the need to demonstrate this concept using mongodb (or any other database). It distracts from the concept and it assumes prior experience with the database in question

Using a database is pretty common, it's a very valid use-case for env vars (probably my most-used case). The choice of Mongo vs MySQL vs whatever is pretty irrelevant.

~ 2 years ago

Yeah I was facing the same problem,

$ brew install mongodb

$ brew services start mongodb

This doesn't seem to work. I recommend just following the mongodb installation instructions instead. https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/