228

Assumed that I have written a module for Node.js which I would like to keep private. I know that I can (should) add the line:

"private": "true"

to the package.json file, and I also know that I can npm install this module using a file system path or a link to a git repository, including GitHub.

I also know that I can put such a file system path or a link to a git repo into package.json, so that the dependencies part may look somewhat like this:

"dependencies": {
  "myprivatemodule": "git@github.com:..."
}

What I now want is not to link to the latest version, but to a specific one. The only possibility I know of is to link to a specific commit using its ID. But this is way less readable and worse maintainable than using a version number such as 0.3.1.

So my question is: Is it possible to specify such a version number anyway and make npm search the git repository for the latest commit that includes this version?

If not, how do you resolve this issue in your projects? Do you live with commit IDs or is there a better solution to this?

Zeeshan Hassan Memon
  • 8,105
  • 4
  • 43
  • 57
Golo Roden
  • 140,679
  • 96
  • 298
  • 425

8 Answers8

303

The accepted answer did not work for me.

Here's what I'm doing to pull a package from github:

npm install --save "git://github.com/username/package.git#commit"

Or adding it manually on package.json:

"dependencies": {
  "package": "git://github.com/username/package.git#commit"
}

Here's the full npm documentation:

https://docs.npmjs.com/cli/v9/configuring-npm/package-json?v=true#git-urls-as-dependencies

surj
  • 4,706
  • 2
  • 25
  • 34
  • 65
    If you're using http/https, make sure you include the "git+" prefix: `"package": "git+https://github.com/username/package.git#commit"` – Ates Goral Oct 24 '14 at 18:22
  • 6
    This worked as far as "npm install" but when I tried to run my application the require('mymodule') failed to find it's package. Even though the package is in the node_modules directory with the same name. – Derrick Jan 27 '16 at 00:16
  • 1
    Oh, the module in question did not include the build with the specific commit I wanted so if you have the same problem you may have to build it manually. – Derrick Jan 27 '16 at 18:27
  • 2
    you can also use `#tag` which usually points at a version number – deltree Apr 28 '16 at 02:41
  • 2
    @surjikal you need to tag a release before you can use version numbers with git. e.g. `git tag -a v1.0.1 && git push --tag && git push` as @Jonathan Lonowski also said in a comment. – dotnetCarpenter May 12 '16 at 19:48
  • You can now do `npm i {owner}/{project}#{tag}` or add `"{library}": "github:{owner}/{project}#{tag}"` to package.json instead of using `git@github.com` or `git://github.com` – user115014 Feb 01 '19 at 10:52
  • 1
    @AtesGoral why should I use the git+ prefix? What's the difference? – iamdeit Aug 09 '19 at 20:50
224

A dependency has to be available from the registry to be installed just by specifying a version descriptor.

You can certainly create and use your own registry instead of registry.npmjs.org if your projects shouldn't be shared publicly.

But, if it's not in a registry, it'll have to be referenced by URL or Git URL. To specify a version with a Git URL, include an appropriate <commit-ish>, such as a tag, at the end as a URL fragment.

Example, for a tag named 0.3.1:

"dependencies": {
  "myprivatemodule": "git@github.com:...#0.3.1"
}

Note: The above snippet shows the base URL the same as it was posted in the question.

The snipped portion (...) should be filled in:

"myprivatemodule": "git@github.com:{owner}/{project}.git#0.3.1"

And, a different address format will be needed when SSH access isn't available:

"myprivatemodule": "git://github.com/{owner}/{project}.git#0.3.1"

Depending on your OS, you may also be able to link to the dependency in another folder where you have it cloned from Github.

Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • 1
    Seems some of the links in this post are outdated, since they lead to 404 pages instead. Which is a pity, since some of this is information I've been looking for for quite a while. – MvG Apr 07 '15 at 17:31
  • 5
    I tagged a specific version with `git tag -a "1.0.0"` and pushed `git push --tags`, then I added the `#v1.0.0` at the end of the `git+ssh` dependency. But at `npm update` nothing happens. – loretoparisi Apr 19 '16 at 08:31
  • 4
    @loretoparisi Sorry. I didn't meant to suggest adding `v` was necessary. After the `#`, the [fragment](https://en.wikipedia.org/wiki/Fragment_identifier) should match the tag's full name (or other *commitsh*) – in your case, `#1.0.0`. – Jonathan Lonowski Apr 19 '16 at 15:51
  • As of July 2016, hosting own registry has gotten more complicated as they are moving from couchdb to microservices – Yan Foto Jul 01 '16 at 09:20
  • 3
    You can now do `npm i {owner}/{project}#{tag}` or add `"{library}": "github:{owner}/{project}#{tag}"` to package.json instead of using `git@github.com` or `git://github.com` – user115014 Feb 01 '19 at 10:50
  • e.g. this works: npm install node-red/node-red#v0.2.0 – human Jul 20 '19 at 16:04
91

If by version you mean a tag or a release, then github provides download links for those. For example, if I want to install fetch version 0.3.2 (it is not available on npm), then I add to my package.json under dependencies:

"fetch": "https://github.com/github/fetch/archive/v0.3.2.tar.gz",

The only disadvantage when compared with the commit hash approach is that a hash is guaranteed not to represent changed code, whereas a tag could be replaced. Thankfully this rarely happens.

Update:

These days the approach I use is the compact notation for a GitHub served dependency:

"dependencies": {
  "package": "github:username/package#commit"
}

Where commit can be anything commitish, like a tag. In the case of GitHub you can even drop the initial github: since it's the default.

qubyte
  • 17,558
  • 3
  • 30
  • 32
  • The archive mode also works for commits; e.g., ` yarn add https://github.com/github/fetch/archive/a2fbf834773b8dc20eef83bb53d081863d3fc87f.tar.gz` – bvj Mar 03 '18 at 05:59
  • Cleanest solution. – Honest Charley Bodkin Jun 03 '20 at 06:44
  • Note that `commit` above needs to be the exact tag name if a tag is being used. When you tag your releases with `v3.0.0` you need to use that exact tag with the `v` prefix. – xh3b4sd Nov 03 '20 at 18:14
16

This command installs npm package username/package from specific git commit:

npm install https://github.com/username/package#3d0a21cc

Here 3d0a21cc is first 8 characters of commit hash.

Prisacari Dmitrii
  • 1,985
  • 1
  • 23
  • 33
9

My example comment to @qubyte above got chopped, so here's something that's easier to read...

The method @surjikal described above works for branch commits, but it didn't work for a tree commit I was trying include.


The archive mode also works for commits. For example, fetch @ a2fbf83

npm:

npm install  https://github.com/github/fetch/archive/a2fbf834773b8dc20eef83bb53d081863d3fc87f.tar.gz

yarn:

yarn add  https://github.com/github/fetch/archive/a2fbf834773b8dc20eef83bb53d081863d3fc87f.tar.gz

format:

 https://github.com/<owner>/<repo>/archive/<commit-id>.tar.gz


Here's the tree commit that required the /archive/ mode:
yarn add  https://github.com/vuejs/vuex/archive/c3626f779b8ea902789dd1c4417cb7d7ef09b557.tar.gz

for the related vuex commit

bvj
  • 3,294
  • 31
  • 30
5

I needed to run two versions of tfjs-core and found that both needed to be built after being installed.

package.json:

"dependencies": {
  "tfjs-core-0.14.3": "git://github.com/tensorflow/tfjs-core#bb0a830b3bda1461327f083ceb3f889117209db2",
  "tfjs-core-1.1.0": "git://github.com/tensorflow/tfjs-core#220660ed8b9a252f9d0847a4f4e3c76ba5188669"
}

Then:

cd node_modules/tfjs-core-0.14.3 && yarn install && yarn build-npm && cd ../../
cd node_modules/tfjs-core-1.1.0  && yarn install && yarn build-npm && cd ../../

And finally, to use the libraries:

import * as tf0143 from '../node_modules/tfjs-core-0.14.3/dist/tf-core.min.js';
import * as tf110 from '../node_modules/tfjs-core-1.1.0/dist/tf-core.min.js';

This worked great but is most certainly #hoodrat

duhaime
  • 25,611
  • 17
  • 169
  • 224
  • 1
    Thank you, I have been trying to import it every other imaginable way. I had to see your snippet to realize I had to import directly from the file. – Victor Ivens Jun 11 '20 at 05:44
3

I describe here a problem that I faced when run npm install - the package does not appear in node_modules.

The issue was that the name value in package.json of installed package was different than the name of imported package (key in package.json of my project).

So if your installed project name is some-package (name value in its package.json) then in package.json of your project write: "some-package": "owner/some-repo#tag".

andrew
  • 412
  • 2
  • 14
  • I wish I found your answer earlier - I just solved, with the same problem making me struggle for a while; and this `name` requirement is not mentioned often on the net.. (not that I could incur in that, at least). – Kamafeather Jul 04 '19 at 22:17
  • *"Add your package dependencies to your package.json specifying the full scoped package name."* - Not really emphasising it: https://help.github.com/en/articles/configuring-npm-for-use-with-github-package-registry#installing-a-package – Kamafeather Jul 04 '19 at 22:20
  • I found out that `npm install --save git+https://` is a pretty safe way to not hit in this problem again in the future. – Kamafeather Jul 04 '19 at 22:23
1

If you're doing this with more than one module and want to have more control over versions, you should look into having your own private npm registry.

This way you can npm publish your modules to your private npm registry and use package.json entries the same way you would for public modules.

https://docs.npmjs.com/files/package.json#dependencies

Igor Soarez
  • 6,335
  • 1
  • 14
  • 14