# Whirlwind tour of (correct) npm usage

<p class="callout info">This article was originally published at [https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2). </p>

This is a quick tour of how to get started with NPM, how to use it, and how to fix it.

<p class="callout success">I'm available for [tutoring and code review](http://cryto.net/~joepie91/code-review.html) :)</p>

### Starting a new project[<svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg>](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2#starting-a-new-project)

Create a folder for your project, preferably a Git repository. Navigate into that folder, and run:

```bash
npm init
```

It will ask you a few questions. Hit `Enter` without input if you're not sure about a question, and it will use the default.

You now have a `package.json`.

<p class="callout warning">*If you're using Express:* Please don't use `express-generator`. It sucks. Just use `npm init` like explained above, and follow the 'Getting Started' and 'Guide' sections on the [Express website](http://expressjs.com/). They will teach you all you need to know when starting from scratch.</p>

### Installing a package[<svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg>](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2#installing-a-package)

All packages in NPM are *local* - that is, specific to the project you install it in, and actually installed *within* that project. They are also nested - if you use the `foo` module, and `foo` uses the `bar` module, then you will have a `./node_modules/foo/node_modules/bar`. This means you pretty much never have version conflicts, and can install as many modules as you want without running into issues.

All modern versions of NPM will 'deduplicate' and 'flatten' your module folder as much as possible to save disk space, but as a developer you don't have to care about this - it will still work like it's a tree of nested modules, and you can still assume that there will be no version conflicts.

You install a package like this:

```bash
npm install packagename
```

While the packages themselves are installed in the `node_modules` directory (as that's where the Node.js runtime will look for them), that's only a temporary install location. The *primary* place where your dependencies are defined, should be in your `package.json` file - so that they can be safely updated and reinstalled later, even if your `node_modules` gets lost or corrupted somehow.

In older versions of npm, you had to manually specify the `--save` flag to make sure that the package is saved in your `package.json`; that's why you may come across this in older articles. However, modern versions of NPM do this automatically, so the command above should be enough.

One case where you *do* still need to use a flag, is when you're installing a module that you just need for developing your project, but that isn't needed when actually *using* or *deploying* your project. Then you can use the `--save-dev` flag, like so:

```bash
npm install --save-dev packagename
```

Works pretty much the same, but saves it as a development dependency. This allows a user to install just the 'real' dependencies, to save space and bandwidth, if they just want to use your thing and not modify it.

To install everything that is declared in `package.json`, you just run it without arguments:

```bash
npm install
```

When you're using Git or another version control system, you should add `node_modules` to your ignore file (eg. `.gitignore` for Git); this is because *installed* copies of modules may need to be different depending on the system. You can then use the above command to make sure that all the dependencies are correctly installed, after cloning your repository to a new system.

### Semantic versioning[<svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg>](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2#semantic-versioning)

Packages in NPM usually use semantic versioning; that is, the changes in a version number indicate what has changed, and whether the change is breaking. Let's take **1.2.3** as an example version. The components of that version number would be:

- **Major version number:** 1
- **Minor version number:** 2
- **Patch version number:** 3

Depending on which number changes, there's a different kind of change to the module:

- **Patch version upgrade (eg. `1.2.3` -&gt; `1.2.4`):** An internal change was made, but the API hasn't changed. It's safe to upgrade.
- **Minor version upgrade (eg. `1.2.3` -&gt; `1.3.0`):** The API has changed, but in a backwards-compatible manner - for example, a new feature or option was added. It's safe to upgrade. You may still want to read the changelog, in case there's new features that you want to use, or that you were waiting for.
- **Major version upgrade (eg. `1.2.3` -&gt; `2.0.0`):** The API has changed, and is not backwards-compatible. For example, a feature was removed, a default was changed, and so on. It is **not** safe to upgrade. You first need to read the changelog, to see whether the changes affect your application.

Most NPM packages follow this, and it gives you a lot of certainty in what upgrades are safe to carry out, and what upgrades aren't. NPM explicitly adopts semver in its package.json as well, by introducing a few special version formats:

- **`~1.2.3`:** Allow automatic patch upgrades, but not minor or major upgrades. Upgrading to `1.2.4` is allowed, but upgrading to `1.3.0` or `2.0.0` is not. You still can't downgrade below `1.2.3` - for example, `1.2.2` is *not* allowed.
- **`^1.2.3`:** Allow automatic patch and minor upgrades, but not major upgrades. Upgrading to `1.2.4` or `1.3.0` is allowed, but upgrading to `2.0.0` is not. You still can't downgrade below `1.2.3` - for example, `1.2.2` or `1.1.0` are *not* allowed.
- **`1.2.3`:** Require this specific version. No upgrades are allowed. You will rarely need this - only for misbehaving packages, really.
- **`*`:** Allow upgrades to whatever the latest version is. You should **never** use this.

By default, NPM will automatically use the **^1.2.3** notation, which is usually what you want. Only configure it otherwise if you have an explicit reason to do so.

A special case are `0.x.x` versions - these are considered to be 'unstable', and the rules are slightly different: the *minor* version number indicates a breaking change, rather than the major version number. That means that `^0.1.2` will allow an upgrade to `0.1.3`, but *not* to `0.2.0`. This is commonly used for pre-release testing versions, where things may wildly change with every release.

If you end up publishing a module yourself (and you most likely eventually will), then definitely adhere to these guidelines as well. They make it a lot easier for developers to keep dependencies up to date, leading to considerably less bugs and security issues.

### Global modules[<svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg>](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2#global-modules)

Sometimes, you want to install a command-line utility such as [`peerflix`](https://www.npmjs.com/package/peerflix), but it doesn't belong to any particular project. For this, there's the `--global` or `-g` flag:

```bash
npm install -g peerflix
```

If you used packages from your distribution to install Node, you may have to use `sudo` for global modules.

**Never, ever, ever use global modules for project dependencies, ever.** It may seem 'nice' and 'efficient', but you will land in dependency hell. It is not possible to enforce semver constraints on global modules, and things will spontaneously break. All the time. Don't do it. Global modules are *only for project-independent, system-wide, command-line tools*.

**This applies even to development tools for your project.** Different projects will often need different, incompatible versions of development tools - so those tools should be installed *without* the global flag. For local packages, the binaries are all collected in `node_modules/.bin`. You can then run the tools like so:

```bash
./node_modules/.bin/eslint
```

### NPM is broken, and I don't understand the error![<svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg>](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2#npm-is-broken-and-i-dont-understand-the-error)

The errors that NPM shows are usually not very clear. I've written a tool that will analyze your error, and try to explain it in plain English. It can be found [here](http://cryto.net/why-is-npm-broken/).

### My dependencies are broken![<svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg>](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2#my-dependencies-are-broken)

If you've just updated your Node version, then you may have native (compiled) modules that were built against the old Node version, and that won't work with the new one. Run this to rebuild them:

```bash
npm rebuild
```

### My dependencies are still broken![<svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg>](https://gist.github.com/joepie91/9b9dbd8c9ac3b55a65b2#my-dependencies-are-still-broken)

Make sure that all your dependencies are declared in `package.json`. Then just remove and recreate your `node_modules`:

```bash
rm -rf node_modules
npm install
```