How to validate environment file in NodeJS
Tags: node, javascript, webdev
Published: 2021-01-08 09:33:45

---
title: How to validate environment file in NodeJS
published: false
description: You will learn how to validating .env file in NodeJS
tags: nodejs, javascript, webdev
cover_image: https://images.unsplash.com/photo-1504805572947-34fad45aed93?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80
published: true
---

I'll show you how to validate .env file with [Joi](https://github.com/sideway/joi) validation. I'm currently using almost all of my [ExpressJS](https://expressjs.com/) apps. So let's go..

# 1. Creating A Project

First let's create a project. We'll use [npm](https://www.npmjs.com/) for creating project. Open your terminal and go to location where you wanna create project folder. Then run the following commands in order.

```
mkdir project-folder-name
cd project-folder-name/
npm init -y
npm install joi dotenv
```

After all commands are executed open your project with your favourite IDE or text editor.

# 2. Creating Config File

In your terminal or IDE create a folder named ***config***. Then inside config folder create a file named ***config.js***.

Terminal command: 
```
mkdir config
cd config/
touch config.js
```

After all commands are executed, our project folder structure will look like this:

![Project folder structure](https://dev-to-uploads.s3.amazonaws.com/i/ow3dxqfisij9tqfibes4.jpg)

# 3. Writing Config Code

Open ***config.js*** file in your IDE or text editor. 

First we'll import our required packages.

```
const dotenv = require('dotenv');
const joi = require('joi');
const path = require('path');
```
### Why are we using these packages?

1. [**dotenv**](https://github.com/motdotla/dotenv) : Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env.
2. [**joi**](https://github.com/sideway/joi) : The most powerful schema description language and data validator for JavaScript.
3. [**path**](https://nodejs.org/api/path.html) : The path module provides utilities for working with file and directory paths. 

After importing packages, we're passing .env file location as an option to dotenv package. At the moment we don't have a .env file yet. We'll create later.

```dotenv.config({ path: path.join(__dirname, '../.env') });```

##### Creating Environment File Schema

```
const envVarsSchema = joi
  .object()
  .keys({
    NODE_ENV: joi
      .string()
      .valid("production", "development", "test")
      .required(),
    PORT: joi.number().postive().required(),
    API_SECRET: joi.string().required().description("My api secret"),
  })
  .unknown();
```

#### What Did We Do?

We created joi object type validation with our environment variable names and determined our rules.

1. ***NODE_ENV***: This key is a string and only accepts 'production', 'development' and 'test'. If we give a different value it'll throw an error. And it's required.
2. ***PORT***: This key is a number and positive. If we give a negative value it'll throw an error. And it's required.
3. ***API_SECRET***: This key is a string and it's required.

##### ***IMPORTANT NOTE***

There's a method named ***unknown*** at the end of the code. It's overrides the handling of unknown keys for the scope of the current object only. (does not apply to children)

We're using this method because; there are dozens of environment variables in ***process.env*** used by our operation system or other programs. So if we don't use this method joi will throw an error.

#### Validating Our Schema

```
const { value: envVars, error } = envVarsSchema
  .prefs({ errors: { label: 'key' } })
  .validate(process.env);
```

We validated joi schema and we got destructured ***'value'*** and ***'error'*** variables from joi validation and we give an alias to ***'value'*** variable named ***'envVars'***.

#### Checking There's An Error

```
if (error) {
  throw new Error(`Config validation error: ${error.message}`);
}
```

If there's an error in schema we will throw an error. 

#### Exporting Our Values

```
module.exports = {
  env: envVars.NODE_ENV,
  port: envVars.PORT,
  apiSecret: envVars.API_SECRET,
};
```

We exported our values as object.

#### Full Code Of config.js File

```
const dotenv = require("dotenv");
const joi = require("joi");
const path = require("path");

dotenv.config({ path: path.join(__dirname, "../.env") });

const envVarsSchema = joi
  .object()
  .keys({
    NODE_ENV: joi
      .string()
      .valid("production", "development", "test")
      .required(),
    PORT: joi.number().positive().required(),
    API_SECRET: joi.string().required().description("My api secret"),
  })
  .unknown();

const { value: envVars, error } = envVarsSchema
  .prefs({ errors: { label: "key" } })
  .validate(process.env);

if (error) {
  throw new Error(`Config validation error: ${error.message}`);
}

module.exports = {
  env: envVars.NODE_ENV,
  port: envVars.PORT,
  apiSecret: envVars.API_SECRET,
};

```

# 4. Creating .env File

Go to project root directory and create a file named ***.env***. Then write your environment variables to this file.

Your .env file should look like this:

```
NODE_ENV="development"
PORT=3000
API_SECRET="secret"
```

# 5. package.json "start" script

Open your ***'package.json'*** file and write your ***'start'*** script.

`"start": "node ."`

My package.json file:

```
{
  "name": "project-folder-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^8.2.0",
    "joi": "^17.3.0"
  }
}
```


# 6. Creating index.js File

Go to project root directory and create a file named ***index.js***. Then write your code.

I'll print my config file to console. Every time i use the config file it'll check my .env file is valid. So using before the application is useful because if there's an error my application will not start.

My index.js File:
```
const config = require("./config/config");

console.log(config);
process.exit(0);

```

Run the start command from your terminal.

`npm run start` or `npm start`

My Output:

![Console Output](https://dev-to-uploads.s3.amazonaws.com/i/5cffz9o7nfaw3fjf7m79.jpg)

# 7. Let's Check Is Validation Working?

I'll remove ***'PORT'*** variable from ***'.env'*** file and will start my application again.

Result: 

![Error](https://dev-to-uploads.s3.amazonaws.com/i/gtg66lhkztfbszxyssvp.jpg)

And it's working as expected. It's throwing an error and saying; "PORT" is required.

---

Thanks to everyone who reads. I hope it was useful.

---

I learned from this repository. Thanks the all contributors!: [https://github.com/hagopj13/node-express-boilerplate](https://github.com/hagopj13/node-express-boilerplate)
Cover Image: [https://unsplash.com/photos/oqStl2L5oxI](https://unsplash.com/photos/oqStl2L5oxI)