76

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,949
  • 7
  • 68
  • 102
DerZyklop
  • 3,672
  • 2
  • 19
  • 27
  • 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

7 Answers7

107

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,886
  • 4
  • 28
  • 33
enrico.bacis
  • 30,497
  • 10
  • 86
  • 115
  • 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
43

You do have a native NPM command:

npm pkg set 'scripts.test'='jest'

Which is really helpful when you want to share a command. Instead of asking someone to install some cli tool, you can simply share this.

BTW, it's even more helpful when you use NPM workspaces, in which case you can change all the packages together:

npm pkg set 'scripts.test'='jest' -ws
Shl
  • 3,130
  • 1
  • 17
  • 16
19

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,893
  • 2
  • 25
  • 41
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
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
  • 42,756
  • 16
  • 135
  • 159
10

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 # creates a git-tag too
npm version 1.0.2 --no-git-tag-version # only changes the version without creating a git-tag
Aakash
  • 21,375
  • 7
  • 100
  • 81
  • 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,448
  • 14
  • 30