📦 How to publish your package on npm
Tags: javascript, npm, node, beginner
Published: 2017-04-08 14:42:09

---
title: ðŸ“¦ How to publish your package on npm
published: true
description: An in-depth guide on how to publish your modules on npm, without pain.
cover_image: https://i.imgur.com/a37Ss7A.jpg
tags: javascript, npm, node, beginner, nodejs, module
---


## An in-depth guide on how to publish your modules on [npm](https://www.npmjs.com/), without pain.

So, you have finished a lib, cli tool, component or some other scripts to want to share with the world.ðŸŒ So it is time to publish it on [npm](https://www.npmjs.com/).

## ðŸ¥‡ Your first package

Let's assume, you already use [npm](https://www.npmjs.com/) for your dependencies. You installed them with `npm install XYZ` or if you're super cool ðŸ˜Ž with [yarn](https://yarnpkg.com/lang/en/)

If you now want to publish your package on npm there is a simple command for that:

```
npm publish
```

ðŸ”¥ But before we do this, we have still some points on our ðŸ“‹checklist. 


## ðŸ“¦ Package.json

You know that all dependencies get saved in your `package.json`. Furthermore you save also relevant information about your package in this file. You can look them up [here](https://docs.npmjs.com/files/package.json)

However the most important would be

- `name`
- `version`
- `description`
- `author`
- `license`
- `repository`
- `main`

The `name` field defines the name your package will have in the registry and people will install your package over the name you define there. `yarn add XYZ` .

The `version` tag defines the version of your package. You really should consider using [semver](http://semver.org/). Because maybe a lot of people will use your package. And there is no worse feeling then breaking peoples production code because you introduce breaking changes but only change the patch version of your package. ðŸ™ˆ

In the `description` field you should add a quick and on-point description, about your package. People will read it if they search for your package on npmjs.org

![npm search](https://i.imgur.com/8hy1rkC.png)

In the `author` field you add your name and e-email, so people know who published the package. It's common to add it in the form of `Name <e-mail>`.

I guess the `license` field is one of the most forgotten fields. People often think it's not *that* important. However if you want people to use your package, maybe even in bigger projects you **definitely** should add a license. So they know if they can use it in commercial projects, what are the restrictions and so on.

You should also add the `repository` field, with a link to the github repo and you can also add the `bugs` field with the link to the github issues page. So people can report bugs and know where to request features.

You can also add `keywords` which help people to find your package if they search for something on npmjs.org


### ðŸ—„ Dependencies

So we all know that you can add dependencies to your project. Or save them as `devDependencies` with `yarn add` or `yarn add -D`

Now if you work on a project like an app or website, it does not make such a big difference if you add your dependencies as a dependency or devDependency. Because they get bundled into a browser build most of the time.

However if you want to publish a package, a lib, a vue component etc. it **is** important to get your dependencies right.

**Dependencies** are required for your lib to work. So if you writing an API or a service and you're using for example [request](https://github.com/request/request) it is a dependency. Because it is needed for your code to run properly.

**DevDependencies** are the one, which are required for the development. Like `eslint` or `xo` for linting or `karma` or `ava` for testing. This is important, because if someone installs your package over `yarn add my-awesome-lib` the `devDependencies` does not get installed! So if you add `request` as a `devDependency` and somewhere in your code you have an `import request from 'request'` this will not work. Because of the missing dependency.

**peerDependencies** are mostly used if you write a plugin for something. Because it requires the user to have the dependency installed already. For example you want to write a plugin for `webpack` and you use some functions of `webpack` and extend them. If you would add `webpack` as a dependency the user would have installed two versions of `webpack` the one which he got installed already for his build process and the one which comes with your plugin. 

Which is nonsense. You would have to update your `package.json` on every release of a new `webpack` patch and update the dependency version.  With `peerDependencies` you say, *Hey look, you need webpack to run my plugin, so install it please. Prefered version is 2.1.x* If someone would install `webpack 2.2.x` your plugin would mostly work, too. There would be a `peerDependency version mismatch` but as long, there would be no breaking changes it would work. This way you give the user freedom to chose the version and upgrade the dependencies.

### ðŸšª Entry Points
Now comes a fun part. The entry points of your lib/package. This one **heavily** depends on the type of your package or lib. Is it a node module? Is it a browser plugin? 
  
The basic entry point will be defined over the `main` field. There you can add your for example `index.js`. If you transpile your source or bundle it, you can define the dist file there.

```
"main": "dist/my-awesome-lib.js",
```

And if you publishing node modules, you will be fine with this one.

But if you're going to publish something for the browser there are more fields to know.

For example the `unpkg` field. If you publish your lib on npm it will be available over [unpkg](https://unpkg.com/#/). It's a CDN so people can pull your scripts into their scripts without installing them over npm.

```
https://unpkg.com/package@version/file
```

In the `unpkg` field you can define the default file, which get served if someone includes `https://unpkg.com/package`.

Most of the time, it is a good practice to define the minified version of your lib there.

```
"unpkg": "dist/my-awesome-lib.min.js",  
```

Last but not least, there are two more fields.

The `module` and `jsnext:main` fields. Which are used by modern build systems like Webpack 2, to grab ES6 Modules.

So you have build your lib. Mostly with modern ES6. People want to use it directly in the browser. So you need to transpile it. But as you also have dependencies, you need to bundle the dependencies into it. So you generate an `UMD` module.

But some people may want to use your package with browserify and gulp. Or with webpack 1. So you need a transpiled and bundled `CommonJs` build. However we now have 2017 and things like tree-shaking are now in fashion. To do so, you need an extra build. A ES Module build. Where most of the functions and statements get transpiled into ES2015, except the import and export statements. 

I think right now, only [Rollup](https://rollupjs.org/) supports ES Modules as a target output. (But you can transpile with with babel,too) So if you have an ES module you can set the entry in the `module` and / or  `jsnext:main` field. 

This way, you serve different builds, for different people and environments.

### â›“ Compatibility

Mostly important for node modules, you can define which minimal version of nodejs should be installed to run your module. Thats important if you're using `async / await` without transpiling it down for example.

```
 "engines": {
    "node": ">=7.8.0"
  },
```

## ðŸš« Ignores and âœ… Files
Okay, now we have our different bundles and builds defined and we are nearly ready to publish our package. However you may have a log of stuff in your git repository. The source, maybe assets, the bundled files etc. It's not smart to include all of this into your npm package. It's a good practice to keep the size small.

First of all, you don't want your generated files in your git repo. So you ignore them in your `.gitignore` 
  
You can also add a [.npmignore](https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package).

If you don't create a `.npmignore` but you have a `.gitignore` npm will exlcude all files defined in the `.gitignore` 

So, we ignored for example our `dist` folder in our `.gitignore` because we don't want it in our repo. Now we need to tell npm, that we want to include this files.

So we add a `files` array in our `package.json`.

```
  "files": [
    "dist"
  ],  
```

You can also be more explicit and add only files

```
  "files": [
    "dist/my-awesome-lib.js",
    "dist/my-awesome-lib.min.js",
    "dist/my-awesome-lib.esm.js"
  ],  
```

## ðŸ’¯ Publish

Now we are ready to publish our package. But because we are developers, and developers are lazy we should add an additional command to our scripts. The `prepublish` command script.

This one runs, before every `npm publish`. So it is good practice to for example clean your node_modules and make a fresh install of the dependencies, lint and test your code and then build your code before a publish. But thats up to you! ðŸ‘‡ðŸ»

```
  "scripts": {
    "prepublish": "yarn run lint && yarn run test && yarn run build"
  },
```

And finally we run `npm publish`. Keep in mind that you need an account on npmjs.org ;)

## ðŸ· Dist-Tags
  
Last topic is a very handy one! Dist-tags. If you publish your package, it will automatically get the **@latest** tag for the version you published it. 
  
People can install your package with a strict version or the latest tag: `yarn add my-awesome-pacakge@0.0.1` or `yarn add my-awesome-pacakge` which is equivalent to `my-awesome-package@latest`

Now there are some circumstances where you will need dist-tags. One is if you support multiple versions of you package. Good examples are webpack, vue and many more. Where you start with a v1 but then working on a v2. 

Let's say your package is at v1.10.0 but you're working on a v2.0.0 release and want people to test it and report issues etc. 

The problem is, that if you simply `npm publish` it, it will get the latest tag. So everyone installing it over `npm install my-lib` will get the unstable v2.0.0 which is not what we want. For this purpose we have tags. You can list your tags with `npm dist-tag ls` and you will get a list of tags and package versions assigned to them.

![dist tags](https://i.imgur.com/brBsbqB.png)

So you can add a tag to your publish command now. 

```
npm publish --tag beta
```

This way the current version v2.0.0 will be tagged with beta. And the `@latest` tag remains on the v1.10.0 

Now you can install it over `npm install my-awesome-lib@beta -D`

ðŸ”¥ **It's important to know that you can only assign one version to a tag. And you can't overwrite changes to a version.**

This is quite important for testing purpose. I learned myself the hard way, that only because your code is working locally and the unit tests pass, this does not mean that the bundled file published on npm will work like you think.

Thats why it's good to test your packages before releasing with the `@latest` tag. You can use the good old release candidates for this. Because if you change the version of your package from 2.0.0 to 2.0.1 and publish it with the `beta` tag, and then you see that you still got a bug into it, you need to publish the next one with 2.0.2. You can't make a change to the 2.0.1 release and publish it with the same version with the latest tag.

Thats why *release candidates* or *beta* postfixes come handy.

You simple set the version in your `package.json` to 2.0.0-rc1 
and publish it with the beta tag. Then you can test it and only bump the rc1 to rc2 etc. If you think you ready to go, you publish it as 2.0.0 â­