705

I want to do something like this, so npm install also installs the package.json of ../somelocallib or more importantly its dependencies.

"dependencies": {
    "express": "*",
    "../somelocallib": "*"
}
user1680104
  • 8,437
  • 4
  • 22
  • 27

20 Answers20

881

npm >= 2.0.0

This feature was implemented in the version 2.0.0 of npm. Local paths can be saved using npm install -S or npm install --save, using any of these forms:

../foo/bar
~/foo/bar
./foo/bar
/foo/bar

Example package.json:

{
  "name": "baz",
  "dependencies": {
    "bar": "file:../foo/bar"
  }
}

npm ls:

app@0.0.1 /private/tmp/app
└── somelocallib@0.0.1 -> /private/tmp/somelocallib

npm < 2.0.0

Put somelocallib as dependency in your package.json as normal:

"dependencies": {
  "somelocallib": "0.0.x"
}

Then run npm link ../somelocallib and npm will install the version you're working on as a symlink.

Reference: link(1)

danilopopeye
  • 9,610
  • 1
  • 23
  • 31
  • 7
    How we can unlink it? – AtaurRehman Asad Mar 27 '14 at 13:39
  • 1
    @AtaurRehmanAsad `npm rm somelocallib` should do the trick. have a look: https://github.com/npm/npm/issues/750 – danilopopeye Mar 28 '14 at 15:18
  • 24
    The downside of installing local packages with "npm link" is that you get a lot of module duplication. When you list your dependencies with "module: version" or "module: git-repo", npm install algorithm avoid to install a package that is already installed in a parent package. So with "npm link", if your main application depends on "async@0.8.0" and all your local packages also depends on "async@0.8.0" you'll end with all local packages installing the "async@0.8.0" instead of using the same installed "async" version of the main application. This doesn't happen using "npm install folder". – Pedro Ballesteros May 14 '14 at 14:11
  • 3
    @PedroBallesteros you can use the `npm dedup` to fix this problem. https://www.npmjs.org/doc/cli/npm-dedupe.html – danilopopeye Jun 20 '14 at 10:30
  • 1
    @danilopopeye I don't like what "npm dedup" makes with the dependency tree and the doc warns you about that: "Note that this operation transforms the dependency tree, and may result in packages getting updated versions, perhaps from the npm registry. This feature is experimental, and may change in future versions." – Pedro Ballesteros Jul 21 '14 at 16:54
  • I see versioning of modules as a big problem here. With this approach, a change in the module reflects to all other modules that depend on it, because they can't select a specific version. This means that API changes of the modules are impossible. – Thomas Fankhauser Sep 27 '16 at 11:27
  • Has anyone had any issue with Travis CI not being able to find a module that has been installed using "file:../"? – Matt Derrick Dec 01 '16 at 18:05
  • FYI, `npm outdated` doesn't like when you do this stuff I found. But they actually install just fine it seems. – Joshua Pinter Mar 06 '17 at 00:15
  • 1
    But the `devDependencies` in the reference file are not being installed, how to specify that ? – Sarath Jul 19 '17 at 14:02
  • 2
    For some reason `~/foo/bar` didn't work when I tried to add it to package.json. I installed the package using `npm install --save` instead, and it set the path to `file:///Users/myuser/foo/bar`. – John Montgomery Aug 08 '17 at 16:49
  • `file:foo/bar` should be normalized as well. – Estus Flask Sep 27 '17 at 11:01
  • 12
    "The local package will be copied ..." does not seem to be the case with a more recent npm version. Now, a symlink is created. – tsauerwein Mar 19 '19 at 08:12
  • @tsauerwein do you have any reference to this change? if so, I can update the answer :) – danilopopeye Mar 23 '19 at 15:39
  • 1
    What if the local dependency package version is updated? Are we able to update it automatically by `npm install`, rather than remove and reinstal? l – Shaohua Huang Apr 29 '19 at 04:16
  • 3
    @danilopopeye Per https://docs.npmjs.com/cli/install `npm install ` description says _Install the package in the directory as a symlink in the current project._ – Herman J. Radtke III May 07 '19 at 18:42
  • 1
    Not working for me on ubuntu, an empty file is created inside the module folder. Works fine on windows. – Sushil Kumar Feb 23 '22 at 18:53
  • @HermanJ.RadtkeIII`npm install ` does not install as a symlink. It installs as a "file:" URL. Using `npm link ` installs as a symlink. – Suncat2000 Apr 27 '22 at 16:49
  • There is also the option to do `npm install --install-links` which will copy files to node_modules rather than create a symlink. – kiwichris Oct 05 '22 at 11:32
253

It is now possible to specify local Node module installation paths in your package.json directly. From the docs:

Local Paths

As of version 2.0.0 you can provide a path to a local directory that contains a package. Local paths can be saved using npm install -S or npm install --save, using any of these forms:

../foo/bar
~/foo/bar
./foo/bar
/foo/bar

in which case they will be normalized to a relative path and added to your package.json. For example:

{
  "name": "baz",
  "dependencies": {
    "bar": "file:../foo/bar"
  }
}

This feature is helpful for local offline development and creating tests that require npm installing where you don't want to hit an external server, but should not be used when publishing packages to the public registry.

Michahell
  • 4,905
  • 5
  • 29
  • 45
  • 28
    In npm v.3+, the normalization is absolute, _not relative_, so you will see something like `"bar": "file:///home/user/src/foo/bar"` – Ron Wertlen Feb 08 '16 at 22:30
  • 36
    How to update local path dependency without version incrementing? – Bohdan Lyzanets Apr 26 '16 at 15:51
  • 5
    By the way, this causes all kinds of trouble when and/or if you try to dockerize your node application, as the standard `node:onbuild` images only copy the current directory, and thus leave out anything in `../foo`. – donmartin May 13 '16 at 15:26
  • 5
    is there any way to integrate this with git+ssh so one can either have a local copy of git repository that they `npm install` from or another git repository on the LAN? When I try the above and npm install from git+ssh it appears to look in the node_modules directory and not attempt to go over git+ssh even though that is how I am installing the top-level package. – Michael Jan 12 '17 at 23:26
  • 3
    Installing work. But this way I'll get "ERR not found" when trying to import the module into my project. – C4d Jun 11 '19 at 11:16
  • 1
    What if I want to specify a version AND a custom path? What is the syntax for that? I've had the worst time locating documentation for this. – Tanoro Aug 06 '19 at 15:14
  • Is that relative to the package.json or from inside the node_modules directory? – William Entriken Aug 17 '19 at 01:49
  • 1
    @Tanoro "What if I want to specify a version AND a custom path?" why would you need to do this? If you're telling it where to look, what will it do with that version number? – Rob Grant Oct 13 '22 at 12:56
  • 1
    Can't edit right now but updated docs link is https://docs.npmjs.com/cli/v9/configuring-npm/package-json#local-paths – N1ngu Mar 07 '23 at 09:56
106

This works for me.

Place the following in your package.json file

"scripts": {
    "preinstall": "npm install ../my-own-module/"
}
Saugat
  • 1,309
  • 14
  • 22
Brian McAuliffe
  • 2,099
  • 1
  • 16
  • 13
  • 4
    Thanks for the suggestion that doesn't require the use of "npm link" – ItalyPaleAle Mar 04 '14 at 23:46
  • It removed `.gitignore` in the module folder, created `.npmignore` and the first time I ran it applied 777 recursively on all folders except `node_modules`. But yes, it installed the dependencies. Using npm version 1.4.14. – L0LN1NJ4 Sep 12 '14 at 14:32
  • used this, but instead of messing with node_modules I've used app_modules – catalint Nov 28 '14 at 12:15
  • 6
    Why not `"dependencies": { "my-own-module": "file:../my-own-module" }` ? – Bohdan Lyzanets Apr 26 '16 at 15:40
  • 4
    I agree with @Bohdan here. localdependencies will do the exact same thing. The advantage of using `npm link` is that you don't need to do `npm install` each time to get your dependencies up to date. – froginvasion May 25 '16 at 11:52
  • 1
    The new npm version 5 symlinks local dependencies now intead of copying them, which is causing problems by itself, and all you have to do is use the file:../my-own-module format listed by @Bohdan. The symlink bit causes other issues, though, w/ things like nodemon. – Severun Dec 06 '17 at 22:12
  • This is the only way that worked for me. Specifying it in the package.json didn't work, since at `npm install` it failed with message that the local module didn't include a package.json file, which was obviously wrong. – Angel Venchev Nov 29 '18 at 11:13
  • This method is pretty safe from complex build reference setups with babel. Linking usually is a mess with WebPack/Transpilers because of the dep dupes. Npm install reconciles deps in the host node_modules and allows transpilation to be flat. – deepelement May 21 '19 at 16:52
  • 1
    This leads me to 'Cannot find module "foo"'. The imports arnt working anymore. – C4d Jun 11 '19 at 11:39
38

This is how you will add local dependencies:

npm install file:src/assets/js/FILE_NAME

Add it to package.json from NPM:

npm install --save file:src/assets/js/FILE_NAME

Directly add to package.json like this:

....
  "angular2-autosize": "1.0.1",
  "angular2-text-mask": "8.0.2", 
  "animate.css": "3.5.2",
  "LIBRARY_NAME": "file:src/assets/js/FILE_NAME"
....
Saugat
  • 1,309
  • 14
  • 22
sreekanth
  • 517
  • 4
  • 4
37

If you want to further automate this, because you are checking your module into version control, and don't want to rely upon devs remembering to npm link, you can add this to your package.json "scripts" section:

"scripts": {
    "postinstall": "npm link ../somelocallib",
    "postupdate": "npm link ../somelocallib"
  }

This feels beyond hacky, but it seems to "work". Got the tip from this npm issue: https://github.com/npm/npm/issues/1558#issuecomment-12444454

SgtPooki
  • 11,012
  • 5
  • 37
  • 46
Taytay
  • 11,063
  • 5
  • 43
  • 49
  • 18
    Why `postinstall` and `postupdate` instead of `preinstall` and `preupdate`? –  Apr 26 '14 at 14:34
  • 3
    Could you explain a bit more what this does. i.e. if I setup a vscode project with multiple root folders (i.e. "multi-root workspace") , will it be able to reflect changes in the module folder immediately for the consuming projects ? - Is that what this hack is about ? – bvdb Jan 10 '19 at 16:16
19

Master project

Here is the package.json you will use for the master project:

"dependencies": {
    "express": "*",
    "somelocallib": "file:./somelocallib"
}

There, ./somelocallib is the reference to the library folder as relative to the master project package.json.

Reference: https://docs.npmjs.com/cli/v7/configuring-npm/package-json#local-paths


Sub project

Handle your library dependencies.

In addition to running npm install, you will need to run (cd node_modules/somelocallib && npm install).

This is a known bug with NPM.

Reference: https://github.com/npm/npm/issues/1341 (seeking a more up-to-date reference)


Notes for Docker

Check in your master package.lock and your somelocallib/package.lock into your source code manager.

Then in your Dockerfile use:

FROM node:10
WORKDIR /app
# ...
COPY ./package.json ./package-lock.json ./
COPY somelocallib somelocallib
RUN npm ci
RUN (cd node_modules/zkp-utils/ && npm ci)
# ...

I use parenthesis in my (cd A && B) constructs to make the operation idempotent.

Dan
  • 3,246
  • 1
  • 32
  • 52
William Entriken
  • 37,208
  • 23
  • 149
  • 195
13

Two steps for a complete local development:

  1. Provide the path to the local directory that contains the package.
{
  "name": "baz",
  "dependencies": {
    "bar": "file:../foo/bar"
  }
}
  1. Symlink the package folder

    cd ~/projects/node-redis    # go into the package directory
    npm link                    # creates global link
    cd ~/projects/node-bloggy   # go into some other package directory.
    npm link redis              # link-install the package
    
itsazzad
  • 6,868
  • 7
  • 69
  • 89
12

Here in 2020, working on a Windows 10, I tried with

"dependencies": {
    "some-local-lib": "file:../../folderY/some-local-lib" 
    ...
}

Then doing a npm install. The result is that a shortcut to the folder is created in node-modules. This doesn't work. You need a hard link - which windows support, but you have to do something extra in windows to create a hard symlink.

Since I don't really want a hard link, I tried using an url instead:

"dependencies": {
    "some-local-lib": "file:///D:\\folderX\\folderY\\some-local-lib.tar" 
     ....
}

And this works nicely.
The tar (you have to tar the stuff in the library's build / dist folder) gets extracted to a real folder in node-modules, and you can import like everything else.
Obviously the tar part is a bit annoying, but since 'some-local-lib' is a library (which has to be build anyway), I prefer this solution to creating a hard link or installing a local npm.

jeeves
  • 1,871
  • 9
  • 25
balieu
  • 139
  • 1
  • 5
  • `"build": "node_modules\\.bin\\tsc",` this worked for me instead of `../` or `~/` or `file:///` – Saugat Thapa Oct 23 '21 at 08:00
  • This archive-based approach worked best for me using ESM modules in TypeScript (Windows 10). Run "npm pack" to create the archive, then "npm i ". That imports perfectly, while the symlink solutions were unable to resolve the module. – Stewii Dec 19 '22 at 01:06
6

With yarn it can be done as

yarn add file:../somelocallib

Shreyash Shetty
  • 103
  • 1
  • 5
6

use workspaces

the disadvantage using the file:../path/to/your-library is that you either have to npm install or using npm link in order to to the changes to take effect in the packages that import your package.

pnpm

if you using pnpm: a better solution is using workspace: protocol: workspace:../path/to/your-library. it will symlink the directory to your node_modules rather than copying it, so any changes at the source immediately take effect.

for example:

  ...
  "dependencies": {
    ...
    "my-package": "workspace:../../dist"
  },

note: this solution is intended to be used in a workspace, so you may need to create pnpm-workspace.yaml (even an empty one) file in the root of your project.

yarn/npm

the setup is the same, but workspace keyword is not available:

  ...
  "dependencies": {
    ...
    "my-package": "../../dist"
  }

also make sure to add 'my-package' to "workspaces" in your package.json file. read more

Eliav Louski
  • 3,593
  • 2
  • 28
  • 52
5

I know that npm install ../somelocallib works.

However, I don't know whether or not the syntax you show in the question will work from package.json...

Unfortunately, doc seems to only mention URL as a dependency.

Try file:///.../...tar.gz, pointing to a zipped local lib... and tell us if it works.

H_I
  • 385
  • 3
  • 8
  • 1
    I add "dependencies": { "somemodule":"file:///./internal_modules/somemodule" } to package.json. It doesn't work. Error code is "npm ERR! code E404". – Jeffrey Jan 10 '14 at 01:37
  • npm i --save ./functions/node_modules/firebase worked for me thanks – danday74 Oct 20 '21 at 12:08
4

Curious.....at least on Windows (my npm is 3.something) I needed to do:

"dependencies": {
 "body-parser": "^1.17.1",
 "module1": "../module1",
 "module2": "../module2",

When I did an npm install ../module1 --save it resulted in absolute paths and not relative per the documentation.

I messed around a little more and determined that ../xxx was sufficient.

Specifically, I have the local node modules checked out to say d:\build\module1, d:\build\module2 and my node project (application) in d:\build\nodeApp.

To 'install', I:

d:\build\module1> rmdir "./node_modules" /q /s && npm install
d:\build\module2> rmdir "./node_modules" /q /s && npm install
d:\build\nodeApp> rmdir "./node_modules" /q /s && npm install

module1's package.json has a dependency of "module2": "../module2"; module2 has no local dependency; nodeApp has dependencies "module1": "../module1" and "module2": "../module2".

Not sure if this only works for me since all 3 folders (module1, module2 and nodeApp) sit on that same level.......

Paul Duncan
  • 181
  • 1
  • 5
3

This worked for me: first, make sure the npm directories have the right user

sudo chown -R myuser ~/.npm
sudo chown -R myuser /usr/local/lib/node_modules

Then your in your package.json link the directory

"scripts": {
 "preinstall": "npm ln mylib ../../path/to/mylib"
}, 
"dependencies": {
  "mylib" : "*"
}
scc
  • 10,342
  • 10
  • 51
  • 65
  • 2
    Symbolic links on Windows are possible since XP http://en.wikipedia.org/wiki/NTFS_symbolic_link. Open the command line as administrator, then run `npm install`. – sod Oct 21 '14 at 09:02
3

I wanted to use a set of local dependencies written in TypeScript, and none of the answers here worked for me. npm install would simply refuse to build the dependencies.

I had to resort to using tsconfig.json to add the packages to my project without marking them as dependencies. My usecase is further complicated by the fact that some dependencies depend on each other, and I wanted all of them to come from the local folder.

Here is my solution:

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@tiptap/*": [
        "tiptap/packages/*/src"
      ]
    }
  }
}

In the example above, I have a local project subfolder named tiptap/ and there are many packages in tiptap/packages/*. The "paths" option will rewrite all @tiptap/foo imports into ./tiptap/packages/foo/src, across both my own files and the files in tiptap/.

It's not a good solution, but it is the only thing that worked for me.

Emily
  • 2,577
  • 18
  • 38
2

Actually, as of npm 2.0, there is support now local paths (see here).

damirv
  • 79
  • 1
  • 2
2

There is great yalc that helps to manage local packages. It helped me with local lib that I later deploy. Just pack project with .yalc directory (with or without /node_modules). So just do:

npm install -g yalc  

in directory lib/$ yalc publish 

in project:

project/$ yalc add lib

project/$ npm install 

that's it.

When You want to update stuff:

lib/$ yalc push   //this will updated all projects that use your "lib"

project/$ npm install 

Pack and deploy with Docker

tar -czvf <compresedFile> <directories and files...>
tar -czvf app.tar .yalc/ build/ src/ package.json package-lock.json

Note: Remember to add .yalc directory.

inDocker:

FROM node:lts-alpine3.9

ADD app.tar /app

WORKDIR /app
RUN npm install

CMD [ "node", "src/index.js" ]
John Tribe
  • 1,407
  • 14
  • 26
2

In 2021 you need to use it like:

npm i my-pkg@file:./path-to-my-pkg.js

# To remove it later
npm un my-pkg

Use .js in the end if its file OR path to folder if its complete package with package.json.

Usage

const myPkg = require('my-pkg')

That works like charm!

Sahil Rajput
  • 318
  • 4
  • 17
  • I had to scroll way too down for this. Just one thing: It seems that on Windows only defining a package.json works – pilau Sep 01 '23 at 08:02
1

Complete local development guide for yarn users:

First add dependency to your main project:

cd main-project
yarn add file:../path/to/your-library

Next, if you want to avoid re-building this dependency every time you change it's source:

cd your-library
yarn link

This will register a link to your-library. Next, use the link you just created in your main project.

cd main-project
yarn link your-library

Now every time you change code in your-library, you don't need to rebuild it and it will automatically be included in your main-project. Yarn link works by creating symlinks in your node_modules folder, read more about it here: https://classic.yarnpkg.com/lang/en/docs/cli/link/

Samuel
  • 2,430
  • 5
  • 31
  • 41
1

file: is directly linking a local folder as the package. If the local folder contains devDependencies it will cause version collisions.

link: is also linking the local folder as the package, but also ignores linked devDepedencies, behaving exactly as a package consumed from NPM, but locally.

TLDR: use link to avoid devDependency conflicts :)

Ivan Sanz Carasa
  • 1,141
  • 8
  • 16
0

Using Module Alias

  1. Install the module-alias package:

    npm i --save module-alias

  2. Add paths to your package.json like this:

    { "_moduleAliases": { "@lib": "app/lib", "@models": "app/models" } }

  3. In your entry-point file, before any require() calls:

    require('module-alias/register')

  4. You can now require files like this:

    const Article = require('@models/article');

Fuad Chonora
  • 19
  • 1
  • 4
  • This could be simply worked around using `npm link` into your lib project, then `npm link your-project` as called in lib/package.json – hdev Aug 24 '23 at 13:09