Skip to content

How to publish to npm in 2023

Posted on:January 2, 2023 at 09:22 AM

This is a guide that describes how to publish an open source package to npm in 2023 and what to look out for. If you want to write and publish a package in 2023 you need to write it in Typescript and publish it as an ES module.

Table of contents

Open Table of contents

0. Prerequisites

  1. A npm account. For this guide we are also using a npm organization where we publish to.
  2. A Github account.

1. Create a repository on Github and clone it

It is not needed to have your code in Git or on Github in order to publish packages to npm, but since this guide is about Open Source packages we want the code to be somewhere where everyone can access it. There are alternatives to Github though.

2. Create a package.json at the root of your repository

Go to the root of your repository and run npm init (if you are using an npm organization run npm init --scope=@your-organization). Your very minimal package.json should look something like this:

{
  "name": "@your-organization/your-package",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Note: Even though that package.json is auto-generated by npm itself it is recommended to use (https://nodejs.org/api/packages.html#package-entry-points):

"exports": {
  ".": "index.js"
}

instead of

"main": "index.js"

3. Add Typescript

Add Typescript with npm install typescript --save-dev and add a tsconfig.json to the root of your project.

Your tsconfig.json can look something like this (this is actually the config file from https://github.com/sindresorhus/tsconfig):

{
	"compilerOptions": {
		"outDir": "dist",
		"target": "es2020",
		"lib": [
			"es2020"
		],
		"isolatedModules": true,
		"module": "node16",
		"moduleResolution": "node16",
		"moduleDetection": "force",
		"allowSyntheticDefaultImports": true, // To provide backwards compatibility, Node.js allows you to import most CommonJS packages with a default import. This flag tells TypeScript that it's okay to use import on CommonJS modules.
		"resolveJsonModule": false, // ESM doesn't yet support JSON modules.
		"jsx": "react",
		"declaration": true,
		"pretty": true,
		"newLine": "lf",
		"stripInternal": true,
		"strict": true,
		"noImplicitReturns": true,
		"noImplicitOverride": true,
		"noUnusedLocals": true,
		"noUnusedParameters": true,
		"noFallthroughCasesInSwitch": true,
		"noUncheckedIndexedAccess": true,
		"noEmitOnError": true,
		"useDefineForClassFields": true,
		"forceConsistentCasingInFileNames": true,
		"skipLibCheck": true
	},
	"include": [
		"src",
	],
	"ts-node": {
		"transpileOnly": true,
		"files": true,
		"experimentalResolver": true
	}
}

Add a build script to your package.json that builds your project:

"scripts": {
  "build": "tsc"
}

Point to your types declaration file by adding this to your package.json:

"types": "./dist/index.d.ts"

4. Mark your package as ES module

Update your package.json and add:

"type": "module",
"engines": {
  "node": ">=14.17"
}

5. Specify what files to include in your package

Add the following attribute to your package.json to specify what files should be included in your package:

"files": [
    "dist"
  ]

6. Publish your package to npm using np

Before you can publish to npm you need to login by running npm login.

You can publish your package using npm publish, but we recommend to us NP for this.

If your are using a free organization in npm you need to add the following attribute to your package.json before publishing:

"publishConfig": {
    "access": "public"
  }

Before running np please check if your package.json looks something like this:

{
  "name": "@your-organization/your-package",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "exports": {
    ".": "./dist/index.js"
  },
  "types": "./dist/index.d.ts",
  "engines": {
    "node": ">=14.17"
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "tsc"
  },
  "publishConfig": {
    "access": "public"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "typescript": "^4.9.4"
  }
}

Since we do not have any tests specified we need to skip the test check when publishing.

To finally publish your package to npm run np --no-tests