A Beginner’s Guide to npm — the Node Package Manager

By Peter Dierx

Node.js makes it possible to write applications in JavaScript on the server. It’s built on the V8 JavaScript runtime and written in C++ — so it’s fast. Originally, it was intended as a server environment for applications, but developers started using it to create tools to aid them in local task automation. Since then, a whole new ecosystem of Node-based tools (such as Grunt and Gulp) has evolved to transform the face of front-end development.

To make use of these tools (or packages) in Node.js we need to be able to install and manage them in a useful way. This is where npm, the node package manager, comes in. It installs the packages you want to use and provides a useful interface to work with them. But before we can start using npm, we first have to install Node.js on our system.

Installing Node.js

Head to the Node.js download page and grab the version you need. There are Windows and Mac installers available, as well as pre-compiled Linux binaries and source code. For Linux, you can also install Node via the package manager, as is outlined here.

For this tutorial we are going to use v.5.7.0 Stable.

Let’s see where node was installed and check the version.

$ which node
$ node --version

To verify that your installation was successful let’s give Node’s REPL a try.

$ node
> console.log('Node is running');
Node is running
> .help
.break Sometimes you get stuck, this gets you out
.clear Alias for .break
.exit  Exit the repl
.help  Show repl options
.load  Load JS from a file into the REPL session
.save  Save all evaluated commands in this REPL session to a file
> .exit

The Node.js installation worked, so we can now focus our attention on npm, which was included in the install.

$ which npm
$ npm --version

Node Packaged Modules

npm can install packages in local or global mode. In local mode it installs the package in a node_modules folder in your parent working directory. This location is owned by the current user. Global packages are installed in {prefix}/lib/node_modules/ which is owned by root (where {prefix} is usually /usr/ or /usr/local). This means you would have to use sudo to install packages globally, which could cause permission errors when resolving third-party dependencies, as well as being a security concern. Lets change that:

Parcel delivery company

Time to manage those packages

Changing the Location of Global Packages

Let’s see what output npm config gives us.

$ npm config list
; cli configs
user-agent = "npm/3.6.0 node/v5.7.0 linux x64"

; node bin location = /usr/local/bin/node
; cwd = /home/sitepoint
; HOME = /home/sitepoint
; 'npm config ls -l' to show all defaults.

This gives us information about our install. For now it’s important to get the current global location.

$ npm config get prefix

This is the prefix we want to change, so as to install global packages in our home directory. To do that create a new directory in your home folder.

$ cd && mkdir .node_modules_global
$ npm config set prefix=$HOME/.node_modules_global

With this simple configuration change, we have altered the location to which global Node packages are installed. This also creates a .npmrc file in our home directory.

$ npm config get prefix
$ cat .npmrc

We still have npm installed in a location owned by root. But because we changed our global package location we can take advantage of that. We need to install npm again, but this time in the new user-owned location. This will also install the latest version of npm.

$ npm install npm --global
/home/sitepoint/.node_modules_global/bin/npm -> /home/sitepoint/.node_modules_global/lib/node_modules/npm/bin/npm-cli.js
└── npm@3.7.5

Finally, we need to add .node_modules_global/bin to our $PATH environment variable, so that we can run global packages from the command line. Do this by appending the following line to your .profile or .bash_profile and restarting your terminal.

export PATH="$HOME/.node_modules_global/bin:$PATH"

Now our .node_modules_global/bin will be found first and the correct version of npm will be used.

$ which npm
$ npm --version

Installing Packages in Global Mode

At the moment we only have one package installed globally — that is the npm package itself. So let’s change that and install UglifyJS (a JavaScript minification tool). We use the --global flag, but this can be abbreviated to -g.

$ npm install uglify-js --global
└─┬ uglify-js@2.6.2
  ├── async@0.2.10
  ├── source-map@0.5.3
  ├── uglify-to-browserify@1.0.2
  └─┬ yargs@3.10.0
    ├── camelcase@1.2.1
    ├─┬ cliui@2.1.0
    │ ├─┬ center-align@0.1.3
    │ │ ├─┬ align-text@0.1.4
    │ │ │ ├─┬ kind-of@3.0.2
    │ │ │ │ └── is-buffer@1.1.2
    │ │ │ ├── longest@1.0.1
    │ │ │ └── repeat-string@1.5.4
    │ │ └── lazy-cache@1.0.3
    │ ├── right-align@0.1.3
    │ └── wordwrap@0.0.2
    ├─┬ decamelize@1.1.2
    │ └── escape-string-regexp@1.0.5
    └── window-size@0.1.0

As you can see from the output, additional packages are installed — these are uglify-js’s dependencies.

Listing Global Packages

We can list the global packages we have installed with the npm list command.

$ npm list --global
├─┬ npm@3.7.5
│ ├── abbrev@1.0.7
│ ├── ansi-regex@2.0.0
│ ├── ansicolors@0.3.2
│ ├── ansistyles@0.1.3
└─┬ uglify-js@2.6.2
  ├── async@0.2.10
  ├── source-map@0.5.3
  ├── uglify-to-browserify@1.0.2

The output however, is rather verbose. We can change that with the --depth=0 option.

$ npm list -g --depth=0
├── npm@3.7.5
└── uglify-js@2.6.2

That’s better — just the packages we have installed along with their version numbers.

At this point you can parse JavaScript files in the terminal with uglifyjs. For example the following command would minify example.js into example.min.js:

$ uglifyjs example.js -o example.min.js

Installing Packages in Local Mode

Installing packages in local mode is done without the --global flag. The package will be installed in your parent working directory in a node_modules folder. Let’s create a project folder in our home directory:

$ mkdir ~/project && cd ~/project
$ npm install underscore
└── underscore@1.8.3
$ ls
$ ls node_modules

Listing Local Packages

Just like global packages we can list local packages with the npm list command.

$ npm list
└── underscore@1.8.3

As you can see we are able to install local packages wherever we want. This also means that we can create another directory and install a different version of underscore.

Uninstalling Local Packages

npm is a package manager so it must be able to remove a package. Let’s assume that the current underscore package is causing us compatibility problems. We can remove the package and install an older version, like so:

$ npm uninstall underscore
- underscore@1.8.3 node_modules/underscore
$ npm list
└── (empty)

Installing a Specific Version of a Package

We can now install the underscore package in the version we want. We do that by using the @ sign to append a version number.

$ npm install underscore@1.8.2
└── underscore@1.8.2
$ npm list
└── underscore@1.8.2

Updating a Package

The latest version of underscore fixed the bug we had earlier and we want to update our package to that version.

$ npm update underscore
underscore@1.8.3 node_modules/underscore
$ npm list
└── underscore@1.8.3

Note: for this to work, underscore has to be listed as a dependency in package.json (see Managing Dependencies).

Searching for Packages

We’ve used the mkdir command a couple of times in this tutorial. Is there a node package that does the same?

$ npm search mkdir
npm WARN Building the local index for the first time, please be patient

There is (mkdirp). Let’s install it.

$ npm install mkdirp
└─┬ mkdirp@0.5.1
  └── minimist@0.0.8

Now create a file mkdir.js:

var mkdirp = require('mkdirp');
mkdirp('foo', function (err) {
    if (err) console.error(err)
    else console.log('Directory created!')

And run it from the terminal:

$ node mkdir.js
Directory created!

Managing the Cache

When npm installs a package it keeps a copy, so the next time you want to install that package, it doesn’t need to hit the network. The copies are cached in the .npm directory in your home path.

$ ls ~/.npm
_locks  minimist  mkdirp  underscore

This directory will get cluttered with old packages over time, so it’s useful to clean it up occasionally.

$ npm cache clean

Managing Dependencies

At the moment we only have two packages installed in our project directory, but that can grow very quickly. Installing dependencies by hand is unwieldy, so we can use a package.json file in our project directory to manage them instead. This can be created with the command npm init

$ npm init
This utility will walk you through creating a package.json file.
Press ^C at any time to quit.
name: (project) demo
version: (1.0.0)
description: Demo of package.json
entry point: (index.js)
test command:
git repository:
author: Sitepoint
license: (ISC)

This creates the following file in our project root:

  "name": "demo",
  "version": "1.0.0",
  "description": "Demo package.json",
  "main": "main.js",
  "dependencies": {
    "mkdirp": "^0.5.1",
    "underscore": "^1.8.3"
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "author": "Sitepoint",
  "license": "ISC"

If you want a quicker way to generate a package.json file use the following:

$ npm init --yes

A package.json file will be created and the name of your directory will be used for the name property.

You can also add private: true to prevent accidental publication of private repositories as well as suppressing any warnings generated when running npm install. Let’s create a new directory and use our package.json file to install our dependencies.

$ mkdir ~/demo && cd ~/demo
$ cp ~/project/package.json ~/demo
$ npm install
$ npm list
demo@1.0.0 /home/sitepoint/demo
├─┬ mkdirp@0.5.1
│ └── minimist@0.0.8
└── underscore@1.8.3

That showed how easily we can install the packages we need in another directory based on our package.json file. But how do we keep it up to date when we install new packages? Well, we can use the --save flag.

$ npm install request --save
$ npm list --depth=0
demo@1.0.0 /home/sitepoint/demo
├── mkdirp@0.5.1
├── request@2.53.0
└── underscore@1.8.3

And our package.json has also been updated:

"dependencies": {
  "mkdirp": "^0.5.1",
  "request": "^2.53.0",
  "underscore": "^1.8.3"

Version Managers

There are a couple of tools available that allow you to manage multiple versions of Node.js on the same machine. One such tool is n. Another such tool is nvm (Node Version Manager). If this is something you’re interested in, why not check out our tutorial: Install Multiple Versions of Node.js using nvm.


In this tutorial, I have covered the basics of working with npm. I have demonstrated how to install Node.js from the project’s download page, how to alter the location of global packages (so we can avoid using sudo) and how to install packages in local and global mode. I also covered deleting, updating and installing a certain version of a package, as well as managing a project’s dependencies.

Are you using npm in your projects? There are thousands of packages on the npm registry and with announcement that jQuery plugins should be published there too, this number will only keep growing. Which ones couldn’t you live without?

  • M S i N Lund

    I have been looking for a way to get more dependencies into my code.

  • TQ White II

    Be careful if you use NPM v3 on pre-existing projects. The NPM overlords have decided that you cannot nest your dependencies. If you accidentally upgrade from v2 to v3, it will completely reorganize your project. This can break things and, if you have an organization you prefer, you’re screwed.

    Also, if you have extraneous projects, ie, ones that are not properly connected with a package file, NPM will very nicely DELETE them for you. Make sure you always have a current backup if you use NPM. It’s dangerous.

    I now install dependencies into a temp file outside my project and copy them in by hand. It’s the only way I can keep control of my structure.

    For me, NPM has stopped being a useful tool and reverted to being a simple library with a bad UI.

    • James Hibbard

      This can break things

      Are you linking directly to files in npm_modules (or how does it break things)?

      Also, if you have extraneous projects, ie, ones that are not properly connected with a package file, NPM will very nicely DELETE them for you.

      I don’t follow. Could you expand on that?

      • TQ White II

        Yes, I could expand. Thanks for asking.

        Yes, I did link to a file in a module. I know. Turns out it was way quicker than moving the module to a place where it would be found naturally. Bad form, I know. But, I wasn’t planning on having one of my main tools reorganize my project.

        I have a library of things that I use for almost every project. It has utilities that I always need. It is a handful of Nodejs modules, eg, Bunyan, and my own things, that I keep in a git repo. I clone it into the root of my projects.

        Recently, I used NPM3 to add a package to the kit and, it told me that basically everything in the directory was “extraneous” and deleted them. Since the library is not a part of a project, there is no package.json that references its components. Again, you might think this is bad form but, it has been working for me for all of my Nodejs years and I like it.

        I consider both of these behaviors heinous. Or, I should say, I consider that there is no flag that allows me to suppress these behaviors to be heinous.

        If I want a program to comment on my development style, I’ll get me some lint, or I’ll dig up some grunt scripts. I will do it on purpose.

        I am working on a project right now that I started before, in NPM2. I have had to do elaborate aliases in my text editing tool so that I don’t have to scroll past dozens of installed packages to find my work. I have another NPM2 project that I have been procrastinating on because I know that NPM3 is going to ruin it’s organization when I get back to it.

        • James Hibbard

          How can I reproduce the extraneous packages problem? npm shouldn’t be deleting stuff without warning. But on the other hand, you can’t be surprised if moving from 2.x.x > 3.x.x (of anything) breaks things .

          • TQ White II

            I’m happy to say that, as of 3.3.12, it no longer does it.

            I promise that I really did observe the problem. I actually experimented with variations on the theme to make sure I wasn’t doing something weird. I’ve been working around it since so I didn’t notice that it changed.

            Thanks for following up with me on this.

            (Now if I can only get an automagic fix for the flat directories problem, I can be happy again.)

          • TQ White II

            Create an empty test directory that has no package.json file.

            Clone the repo


            into node_modules.

            Take a look at the contents of


            It will have directories such as environmentChanges or lodash and some others.

            Install your favorite demo NPM module against that node_modules directory.

            Afterwards, that directory (node_modules/qtools/node_modules/) will be gone as will all the contents. The files will not be hoisted into the top level or anywhere else.

          • James Hibbard


            mkdir -p test/node_modules
            cd test/node_modules/
            git clone

            Then in which directory should I run npm install whatever?

          • TQ White II

            I would have run
            mkdir test
            cd test

            git clone node_modules

            #still in test, containing node_modules holding my code

            npm install …

          • James Hibbard

            Ah gotchya. Yeah, it does delete qtools/node_modules — that’s unfortunate. I guess the reason for this happening in npm3 is that they fixed the problem with deeply nested node_modules directories breaking the Windows file system (see here).

            Anyway, it seems to me that you have a bunch of modules (some regular ones on npm and some you wrote yourself) which you are wanting to include in new projects (tell me if I got that wrong). Why not separate out your own modules into their own GitHub repos and then specify everything you need in a package.json file in the root of your project? (it’s possible to use npm to install modules from GitHub, too). Each of these modules should specify its dependencies in its own package.json file, rather than having them committed along with the module (taking up space). They would then be pulled in as part of the install process too.

            Given the above, all you would need to do when starting a new project is copy the package.json file and run npm install.

          • TQ White II

            Told ya! ;-)

            One of these days, I will restructure it, I suppose. I already realized that but I’ve been so bitter about the changes to npm that I can barely work. Reading that this was done because of Windows makes me want to jump out of a Window. I thought I was done having my life wrecked by Microsoft when everyone agreed not to support IE.old. That they won’t give me a switch changes me from suicide to murder.

            But, if you know anyone in the world of npm, tell them to stop deleting files. The flat directory sucks but having files deleted (not moved to the trash) is unacceptable.

            Thanks for the interaction. It’s been fun.

    • James Hibbard

      This can break things

      Are you linking directly to files in npm_modules (or how does it break things)?

      Also, if you have extraneous projects, ie, ones that are not properly connected with a package file, NPM will very nicely DELETE them for you.

      I don’t follow. Could you expand on that?

    • M S i N Lund

      Why on earth would anyone use something like that?

  • 前端小武


  • Craig Buckler

    Another quick tip: show your outdated modules with `npm outdated`

  • miliu99 .

    I always wondered why do I need to install the whole third-party packages using npm for developing my node.js app? Wouldn’t it be enough to just download the js files?

    • James Hibbard

      I suppose you could do that, but why would you want to. What about when packages depend on other packages?

  • Michael

    Just a correction on this line,

    $ node. mkdir.js
    Directory created!

    you have a dot that shouldn’t be there.

    • James Hibbard

      Fixed. Thank you :)

  • Alex Mills

    sudo chown -R $(whoami) $(npm root) $(npm root -g) /// is best

    • Paweł Grzybek

      Great snippet, thanks.

  • Geeta Puri

    Hi, I am just starting to learn node and ionic. In my previous attempt to install ionic, I was having all these ownership issues. Following your article step by step has made life a lot easier for me :) One question, all these pacakges – cordova, ionic, should they be installed as global or local packages? Whats the difference between these anyway? (I mean global and local packages)

    • James Hibbard

      Local packages are available to a specific folder, global packages are available, well, globally. As to whether local or global, I think that every project should bundle its own dependencies to make sure that other developers working on the same code base use the same tools.

  • Filip Rydlo

    Just to let Ya know: When You (or I) run the Searching for Packages [on n stable] on a cheapest hosting virtual server… it will run out of memory.

    So, this is an opportunity for the developers to enhance the *npm search*, because it means there is room for improvement – in possible memory-wise optimizations: i.e. to detect memory limit and (maybe?) to swap some data to disk accordingly [before the limit is HIT] in the process of the *First* index building.
    —- see the error below—-

    npm search mkdir

    103247 ms: Mark-sweep 849.9 (1211.3) -> 849.3 (1219.3) MB, 21274.6 / 0 ms (+ 695.4 ms in 638 steps since start of marking, biggest step 61.5 ms) [allocation failure] [GC in old space requested].
    106317 ms: Mark-sweep 849.3 (1219.3) -> 824.4 (1197.1) MB, 3065.2 / 0 ms [allocation failure] [GC in old space requested].
    108208 ms: Mark-sweep 824.4 (1197.1) -> 824.3 (1190.1) MB, 1891.4 / 0 ms [last resort gc].
    110092 ms: Mark-sweep 824.3 (1190.1) -> 824.3 (1183.1) MB, 1883.6 / 0 ms [last resort gc].

    ==== JS stack trace =========================================

    Security context: 0x1529445c9e59
    1: fromString(aka fromString) [buffer.js:234] [pc=0x25cbd0c5e49] (this=0x152944504189 ,string=0x1b8a8157d119 ,encoding=0x1529445d7aa9 )
    2: from [buffer.js:131] [pc=0x25cbd0543d6] (this=0x268ca2fdb249 ,value=0x1b8a8157d119 ,encodingOrOffset=0x152944…

    FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed – JavaScript heap out of memory

  • Filip Rydlo

    Excellent guide! Thanx a lot.

  • brentxscholl

    How do you edit the .bash_profile?

    i tried
    touch ~/.bash_profile; open ~/.bash_profile
    But when i put
    which npm
    it still gives me /usr/local/bin/npm

    • James Hibbard

      Which OS are you using?

  • Gagandeep Singh


  • Sebastian Herrera


  • Nguyễn Đức Đông


  • Faron the Falcon

    This article on introduction to node.js is easily found all across the net, and from reading articles, this all really pretty much same to many others. However your article has won a merit compared to rest of others since you did discuss the global of node.js. That is G r E a T! There are numerous benefits in switching between local & global, which will help coders being more closer to the technology edge.

    Benefits of local vs global are often overlooked. So, while “thinking out of the box”, let’s see global as “parent box” and local is actually a “child box” that is inside the parent box. Setting your project blended with both of “boxes” will give you the full benefits that node.js have to offer. In other words, if you dont know local vs global, then you are missing out …fairly lots. :)

    Your article is now my pick #1 because it offers so simple solution in making global to work, and takes few so simple tasks to fix the configuration so local & global can function. This really does eliminate the hassle on having to make request from IT administrators for sudo access to be set up for you which would be bit time-consuming.

    Great thought out article and …heh…I banged my head thinking “of course, why I didn’t think of that?” after realising how simple it can be when it comes to system engineering working with file system.

    Great article!!



Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in JavaScript, once a week, for free.