Using Hocon with Next.js

September 8, 2020

When developing an application you have to keep in mind that the application will run on different environments or configurations. For example when developing locally the database would be different from the database configuration in your production or staging environment.

A common way to configure your application is by using environment variables. Next.js has built-in support to handle environment variables for example using a .env.local file.

The contents of an environment file could look like this (taken from next.js documentation):

# Database
DB_HOST=localhost
DB_USER=myuser
DB_PASS=mypassword

This format works when you don't need many parameters, and the file stays small, but this becomes more and more complex to manage when your list of configuration parameters grows.

Using HOCON

Also known as Human-Optimized Config Object Notation is a configuration file format based on JSON but easier to read and manage for humans. I first starting using HOCON in PLAY Framework projects and found that when your configuration grows it is much easier to maintain than standard environment files which are commonly used in node.js projects.

An example HOCON file could be:

# PostgreSQL
database {
    hostname = "localhost"
    username = "myuser"
    password = "mypassword"
    timeout = 30s
}

# Redis
redis {
    servers = [ 
        "localhost:6379"
        "localhost:6379"
    ]
}

log {
    # possible options: warning, error, debug, info
    level = "debug" 
    file = "application.log"
}

The above example only shows a minor subset of all the features that HOCON provides:

  • nested object syntax
  • using array at redis.servers
  • using duration format at database.timeout

The complete syntax can be found in the documentation

Setup

Lets add this to a new next.js project. Add the following packages:

  • yarn add @pushcorn/hocon-parser which parses the HOCON file format
  • yarn add env-cmd pushes the HOCON format to environment variables (with a little help from a custom script)

But wait! Wasn't HOCON supposed to replace environment variables? Yes, but next.js still requires the variables to be passed as environment variables to the node.js process. These variables will then be available on the browser side.

After that open up package.json and in "scripts" replace

"dev": "next dev"

with

"dev": "env-cmd next dev"

Now to transform the HOCON to a format that env-cmd understands we need some code. Add a .env.js to the root directory. env-cmd will automatically detect this file and use it to read environment variables. Add the following code to the file:

const path = require("path");
const parse = require("@pushcorn/hocon-parser");

function flattenObj(obj, parent, res = {}) {
  for (let key in obj) {
    let propName = parent ? parent + "_" + key : key;
    if (typeof obj[key] == "object") {
      flattenObj(obj[key], propName, res);
    } else {
      res[propName] = obj[key];
    }
  }
  return res;
}

module.exports = new Promise(async resolve => {
  const file = path.join(__dirname, "config/main.conf");
  const config = await parse({ url: file });

  let envMap = {};
  Object.entries(flattenObj(config)).forEach(([name, value]) => (envMap["NEXT_PUBLIC_" + name.toUpperCase()] = value));

  resolve(envMap);
});

This loads the file, parses the HOCON, flattens the nested structure to a flat structure (database.hostname becomes databasehostname), prepends NEXT_PUBLIC and transforms the names to full uppercase.

The last step is to create a config file in the config/ directory named main.conf

web {
  title = HOCON test
}

The title variable will become NEXT_PUBLIC_WEB_TITLE. Try adding it to a React component using {process.env.NEXT_PUBLIC_WEB_TITLE}

Made with by Rovak