Search code examples
postgresqlherokuknex.jsheroku-postgres

Heroku PG Database migration defaulting to production when NODE_ENV is set to staging


My app uses Express, Knex and PG library. I have set up my NODE_ENV in Heroku to staging using the command https://devcenter.heroku.com/articles/nodejs-support#runtime-behavior (source):

Setting NODE_ENV and restarting    
NODE_ENV: staging

I have a staging env in knexfile:

require('dotenv').config();

module.exports = {
    test: {
        client: 'pg',
        connection: process.env.DB_URL_TEST,
        migrations: {
            directory: './db/migrations',
        },
        seeds: {
            directory: './db/seeds/dev',
        },
        useNullAsDefault: true,
    },
    development: {
        client: 'pg',
        connection: process.env.DB_URL,
        migrations: {
            directory: './db/migrations',
        },
        seeds: {
            directory: './db/seeds/dev',
        },
        useNullAsDefault: true,
    },

    staging: {
        client: 'pg',
        connection: process.env.DATABASE_URL,
        migrations: {
            directory: './db/migrations',
        },
        seeds: {
            directory: './db/seeds/dev',
        },
        useNullAsDefault: true,
    },

    production: {
        client: 'pg',
        connection: process.env.DB_URL_PRODUCTION,
        migrations: {
            directory: './db/migrations',
        },
        seeds: {
            directory: './db/seeds/production',
        },
        useNullAsDefault: true,
    },
};

My db config file listens to NODE_ENV:

    const knex = require('knex');
const config = require('../knexfile');

const dbEnv = process.env.NODE_ENV;

module.exports = knex(config[dbEnv]);

No other config var in Heroku:

enter image description here

When I run a heroku migration it keeps on defaulting to production env:

Running knex migrate:latest
Using environment: production

The only way I have found to force the migration into staging env is to set NODE_ENV to staging as a Heroku env variable explicitly. I don't understand why staging env is not picked up when running the migration.

edit: converted 1st and 3rd screenshot to text. Can't really change the other, it is just a screenshot of a portion of Heroku env variables.

** edit 2**: added the command to set NODE_ENV to staging


Solution

  • Chatted with Heroku customer support, find below their answer which solved my issue:

    This doesn't come from NODE_ENV but from a side-effect of setting NPM_CONFIG_PRODUCTION=true. Refer this article for details.

    Set to true to run in "production" mode.

    devDependencies are not installed at the topmost level when running local npm install without any arguments. Set the NODE_ENV="production" for lifecycle scripts. This behavior is non-intuitive, so we try to warn about it in the build log:

    -----> Creating runtime environment

       NPM_CONFIG_LOGLEVEL=error
       NPM_CONFIG_PRODUCTION=true
       NODE_VERBOSE=false
       NODE_ENV=staging
       NODE_MODULES_CACHE=true
    
       npm scripts will see NODE_ENV=production (not 'staging')
       https://docs.npmjs.com/misc/config#production The functionality of user-env-compile is now built into the standard build process.
    

    NODE_ENV is not set by default on Heroku. What you're seeing is the result of NPM_CONFIG_PRODUCTION during build. That is true by default during builds (it dramatically speeds them up by not installing devDependencies). Npm sets NODE_ENV to production whenever NPM_CONFIG_PRODUCTION is true:

    -----> Node.js app detected

    -----> Reading application state package.json... build directory... cache directory... environment variables...

       Node engine:         0.10.x
       Npm engine:          unspecified
       Start mechanism:     Procfile
       node_modules source: package.json
       node_modules cached: true
    
       NPM_CONFIG_PRODUCTION=true
       NODE_MODULES_CACHE=true If you'd like to disable production mode for npm, you can set NPM_CONFIG_PRODUCTION to false using the
    

    command heroku config:set NPM_CONFIG_PRODUCTION=false -a This will prevent npm from overriding NODE_ENV.