Search code examples
herokuenvironment-variablesheroku-postgresnconf

How to read Heroku's nested process.env vars / object in nconf?


I'm trying to deploy Ghost 1.2.0 to Heroku. With previous versions of Ghost (<= 0.11.x), they used a config.js file where you could just do:

database: {  
    client: 'postgres',
    connection: {
        host: process.env.POSTGRES_HOST,
        user: process.env.POSTGRES_USER,
        password: process.env.POSTGRES_PASSWORD,
        database: process.env.POSTGRES_DATABASE,
        port: process.env.POSTGRES_PORT
    },
    debug: false
}, …

But in this version they're using nconf that replaces this config.js for environment dependent JSON files like config.production.json.

JSON files unlike JS objects can't have vars as values. I could hardcode my credentials to the JSON file, but I don't want to do that because:

  1. Looks like a bad practise to me, and
  2. Heroku rotates credentials periodically and updates applications where this database is attached. (Quoted from Heroku)

After some digging into nconf README and issues I understood that it would be possible to imitate this expected database object just with:

nconf.env({                                                                                                            
    separator: '__' // Two dashes
});

and defining vars as:

heroku config:set DATABASE__CLIENT=postgres
heroku config:set DATABASE__CONNECTION__HOST=<value>
...

but, no matter what, I get undefined when I later call:

nconf.get('database');
nconf.get('DATABASE'); // In case it was case-sensitive...

Instead, if I call:

nconf.get('DATABASE__CLIENT'); // postgres

it works. I could try (and I will) to modify Ghost scripts to read all variables this way, but as long as it expects a database object it'll be so cool to get it working the right way.

So, has anybody figured out how to correctly recreate an object with Heroku's env vars?


Solution

  • I've finally found the solution.

    Unless you want to modify nconf.env(settings) like:

    nconf.env({                                                                                                            
        separator: '__', // Two dashes
        lowerCase: true
    });
    

    This will make it possible to pass lowerCase: true to env() so that if an environment variable is called SOMETHING or SOMEthing, it will also be gettable using something [Source]

    I recommend to use already lowercase env vars.

    So,

    heroku config:set database__client=postgres
    

    will be readable using:

    nconf.get('database:client');
    

    Looks like nconf has a different character separator to define nested variables called separator and another one to read them called logicalSeparator (its default value is :)