How to use environment variables in package.json

node.jsHerokuNpmpackage.json

node.js Problem Overview


Because we don't want sensitive data in the project code, including the package.json file, using environment variables would be a logical choice in my opinion.

Example package.json:

  "dependencies": {
    "accounting": "~0.4.0",
    "async": "~1.4.2",
    "my-private-module":"git+https://${BB_USER}:${BB_PASS}@bitbucket.org/foo/bar.git"

Is this possible?

The question is not if this is wise or not good, just if it's possible.

node.js Solutions


Solution 1 - node.js

In case you use .env file, let's use grep or eval to get a value environment variable from the .env file.

Updated start2 as @Paul suggested:

"scripts": {
    "start": "NODE_ENV=$(grep NODE_ENV .env | cut -d '=' -f2) some_script",
    "start2": "eval $(grep '^NODE_ENV' .env) && some_script"
}

Solution 2 - node.js

I have similar but different requirement. For me, I want to use environment variables in the scripts.

Instead of using the environment variables directly in package.json, I do:

"some-script": "./scripts/some-script.sh",

And in some-script.sh:

#!/bin/sh

npm run some-other-script -- --prop=$SOME_ENV_VAR

Solution 3 - node.js

No, it's not possible. You should access the repo using git+ssh, and store a private key in ~/.ssh.

Your line then looks like:

"my-private-module":"git+ssh://[email protected]/foo/bar.git"

Which doesn't contain anything sensitive.

Solution 4 - node.js

Here's how I managed to work around package.json to achieve the same purpose. It uses a script that reads from a custom section of package.json for URL modules, interpolates environment variables in them, and installs them with npm install --no-save (the --no-save could be omitted, depending on the usecase).

As a bonus: it tries to read the env variable from .env.json, which can be gitignore'd, and very useful for development.

  1. Create a script that will read from a custom section of package.json

env-dependencies.js

const execSync = require('child_process').execSync
const pkg = require('./package.json')

if (!pkg.envDependencies) {
  return process.exit(0)
}

let env = Object.assign({}, process.env)

if (typeof pkg.envDependencies.localJSON === 'string') {
  try {
    Object.assign(env, require(pkg.envDependencies.localJSON))
  } catch (err) {
    console.log(`Could not read or parse pkg.envDependencies.localJSON. Processing with env only.`)
  }
}

if (typeof pkg.envDependencies.urls === 'undefined') {
  console.log(`pkg.envDependencies.urls not found or empty. Passing.`)
  process.exit(0)
}

if (
  !Array.isArray(pkg.envDependencies.urls) ||
  !(pkg.envDependencies.urls.every(url => typeof url === 'string'))
) {
  throw new Error(`pkg.envDependencies.urls should have a signature of String[]`)
}

const parsed = pkg.envDependencies.urls
  .map(url => url.replace(/\${([0-9a-zA-Z_]*)}/g, (_, varName) => {
    if (typeof env[varName] === 'string') {
      return env[varName]
    } else {
      throw new Error(`Could not read env variable ${varName} in url ${url}`)
    }
  }))
  .join(' ')

try {
  execSync('npm install --no-save ' + parsed, { stdio: [0, 1, 2] })
  process.exit(0)
} catch (err) {
  throw new Error('Could not install pkg.envDependencies. Are you sure the remote URLs all have a package.json?')
}
  1. Add a "postinstall": "node env-dependencies.js" to your package.json, that way it will be run on every npm install

  2. Add your private git repos to package.json using the URLs you want (note: they all must have a package.json at root!):

"envDependencies": {
  "localJSON": "./.env.json",
  "urls": [
    "git+https://${GITHUB_PERSONAL_ACCESS_TOKEN}@github.com/user/repo#semver:^2.0.0"
  ]
},

(the semver specifier #semver:^2.0.0 can be omitted, but refers to a git tag, which can be very useful, as it makes your git server a fully-fledge package manager)

  1. npm install

Solution 5 - node.js

No it isn't possible as npm does not treat any string values as any kind of templates.

It may be better to just use git+ssh (if your provider supports it) with an ssh agent.

Solution 6 - node.js

You can use environment values to inject in your package.json like this:

> Any environment variables that start with npm_config_ will be interpreted as a configuration parameter. For example, putting npm_config_foo=bar in your environment will set the foo configuration parameter to bar. Any environment configurations that are not given a value will be given the value of true. Config values are case-insensitive, so NPM_CONFIG_FOO=bar will work the same.

https://docs.npmjs.com/misc/config#environment-variables

Solution 7 - node.js

I had the same need and my solution was based on @Long Nguyen's response. This way, I can only rely on what's defined on the .env file.

.env

...
SKIP_PREFLIGHT_CHECK=true
...

package.json

...
"scripts": {
  "test": "yarn cross-env $(grep SKIP_PREFLIGHT_CHECK ../../.env) react-app-rewired test --watchAll=false"
}
...

Solution 8 - node.js

For complicated environment variables, you can use https://stedolan.github.io/jq/ to access JSON file (env file at your case) JSON file could be something like

{
    "env" :
     {  
            "username" : "1345345",
            "Groups" :  [],
            "arraytest" : [
               {
                  "yes" : "1",
                  "no" : "0"
               }
             ]
     }
}

so the script could be something like this to access yes value

"scripts": {
    "yes": "jq [].arraytest[0].yes?"
}    

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkaasdudeView Question on Stackoverflow
Solution 1 - node.jsLong NguyenView Answer on Stackoverflow
Solution 2 - node.jstechguy2000View Answer on Stackoverflow
Solution 3 - node.jsSteve BennettView Answer on Stackoverflow
Solution 4 - node.jsChristophe MaroisView Answer on Stackoverflow
Solution 5 - node.jsmscdexView Answer on Stackoverflow
Solution 6 - node.jshakuninView Answer on Stackoverflow
Solution 7 - node.jspsergiocfView Answer on Stackoverflow
Solution 8 - node.jsAmrView Answer on Stackoverflow