67

I'm trying to add or edit a variable in my package.json from a shell script. So if i have a package.json like this:

{
  "name": "my-project",
  "description": "Project by @DerZyklop",
  "version": "0.0.0",
  ...

I want a command like

npm config set foo bar

that adds a new field like

{
  "name": "my-project",
  "description": "Project by @DerZyklop",
  "foo": "bar",
  "version": "0.0.0",
  ...

...but unfortunately npm config set just edits the ~/.npmrc and not my package.json.

Al-Mothafar
  • 7,266
  • 6
  • 68
  • 96
DerZyklop
  • 3,384
  • 2
  • 17
  • 25
  • you can just open it with nano and edit it manually... – MightyPork Aug 15 '14 at 18:08
  • @MightyPork sorry if i haven'd expressed myself well enaugh. in the end i want to have a shell script that (among other tasks) edits one of the values inside package.json. – DerZyklop Aug 15 '14 at 19:35

6 Answers6

105

The package.json is just a json file, so you could use the tool json. To install it use:

npm install -g json

Then you can edit a file in-place. More information here.

Example

$ cat package.json
{
  "name": "my-project",
  "description": "Project by @DerZyklop",
  "version": "0.0.0"
}

$ json -I -f package.json -e "this.foo=\"bar\""
json: updated "package.json" in-place

$ cat package.json
{
  "name": "my-project",
  "description": "Project by @DerZyklop",
  "version": "0.0.0",
  "foo": "bar"
}
bounav
  • 4,569
  • 4
  • 26
  • 33
enrico.bacis
  • 29,025
  • 10
  • 83
  • 113
  • 1
    thanks a lot for your help. although i already wrote my script in node [like this](http://stackoverflow.com/questions/10685998/how-to-update-a-value-in-a-json-file-and-save-it-through-node-js). But i also testet your proposal and it works as well. – DerZyklop Aug 19 '14 at 09:03
  • How can "bar" be a variable instead of a concrete value? Tried using an environmental variable but didn't replace it – masimplo Nov 16 '16 at 15:40
  • 2
    @masimakopoulos: assuming that you are talking about bash, string interpolation is only available for double-quoted strings. So you need to swap single-quotes and double-quotes like this: `"this.foo='$A'"`. (This is normal bash behavior, so you can test it with `echo "this.foo='$A'"`) – enrico.bacis Nov 16 '16 at 16:42
  • Thanks. I used your approach to add the default "start" key pointing to a index.js script in my package.json (which was not a default included by Yarn but was called when running my Docker image) `npm install -g json; json --in-place -f package.json -e 'this.scripts={"start": "node index.js"}'` – Luke Schoen Apr 24 '17 at 00:12
  • 5
    Example didn't work for me (something must have changed) due to quoting issue described here: https://github.com/trentm/json/issues/117#issuecomment-322848900 - the command that works for me is using double quotes like this: json -I -f package.json -e "this.foo=\"bar\"" – Elijah Lofgren Oct 13 '17 at 22:31
  • If you only have the `json` package installed as a project dependency, use `npx json` when running the command. – silkfire Mar 08 '22 at 11:04
14

If you don't want to install sponge or json, you can also do

echo "`jq '.foo="bar"' package.json`" > package.json
Amy Guo
  • 151
  • 1
  • 5
13

If you don't want to install anything, you can also use a one-line script to modify the package.json:

node -e "let pkg=require('./package.json'); pkg.homepage='${CI_PAGES_URL}'; require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2));"
ralfstx
  • 3,591
  • 1
  • 23
  • 40
10

You can also use and sponge (moreutils package) like this :

jq '.foo="bar"' package.json | sponge package.json

With an environment variable :

jq --arg h "$HOMEPAGE" '.homepage=$h' package.json | sponge package.json
Bertrand Martel
  • 38,018
  • 15
  • 115
  • 140
5

I wanted to update only the version property in package.json and this is what worked for me:

# this sets the version 
# in package.json to 1.0.2
npm version 1.0.2 
Aakash
  • 17,638
  • 6
  • 93
  • 73
  • 4
    Keep in mind it [also creates tags for that version](https://docs.npmjs.com/cli/v7/commands/npm-version#description). If they're not desired, use `--no-git-tag-version`. – Zebiano Feb 16 '22 at 21:59
4

There's also a npm package for doing this called npe: https://github.com/zeke/npe

cd some/node/project

# Get stuff from package.json
npe name
npe scripts
npe scripts.test
npe repository.url
open $(npe repository.url)

# Set stuff in package.json
npe name foo
npe scripts.start "node index.js"

# Keywords string will be turned into an array
# If commas are present, they'll be the delimiter. Otherwise spaces.
npe keywords "foo, bar, cheese whiz"
npe keywords "foo bar baz"

# The current working directory's package.json is used by default,
# but you can point to another package file with a flag:
npe name --package=some/other/package.json
npe name other --package=some/other/package.json
Zeke
  • 1,440
  • 14
  • 30