Skip to content

Publishing Your Own npm Package

Beginning of the lesson

Publishing Your Own npm Package

Take a small library from a local file to a versioned, installable package the whole ecosystem can use

Big idea: Every course so far has consumed packages with npm install. Now you flip the arrow and become a producer. Publishing is not magic: a package is just a folder with a well-formed package.json manifest and a tarball uploaded to a registry. Get the manifest right and the rest is three commands.
By the end you will be able to:
  • write a publish-ready package.json -- name, version, exports, files, license, engines;
  • choose the correct semantic version bump for any change;
  • expose entry points with the modern exports map, including dual ESM/CJS builds;
  • control exactly which files ship using files vs .npmignore;
  • publish a scoped package publicly and manage the deprecate/dist-tag lifecycle.

1. package.json -- the manifest that defines your package

A package is identified to the registry by exactly two fields: its name and its version. Together they form an immutable coordinate -- @acme/slugify@1.0.0 means one specific tarball that can never be changed once published. Everything else in the manifest describes how that tarball is resolved and installed.

{
  "name": "@acme/slugify",
  "version": "1.0.0",
  "description": "Turn any string into a clean URL slug",
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    }
  },
  "files": ["dist", "README.md"],
  "keywords": ["slug", "slugify", "url", "seo"],
  "license": "MIT",
  "engines": { "node": ">=18" },
  "repository": { "type": "git", "url": "git+https://github.com/acme/slugify.git" },
  "publishConfig": { "access": "public" }
}

The fields that matter most at publish time:

  • name -- globally unique on the registry. Lowercase, URL-safe; may be scoped like @acme/slugify.
  • version -- a semver string; must be higher than any version already published under that name.
  • exports -- the modern entry-point map (supersedes main). It declares precisely what consumers may import.
  • files -- an allow-list of what goes into the tarball. Without it, npm ships nearly everything in the folder.
  • license -- an SPDX identifier such as MIT; omitting it makes your package legally unusable by many teams.
  • engines -- the Node versions you support, e.g. "node": ">=18"; a warning, not a hard block, for consumers.

Dependencies split three ways. dependencies are installed automatically for your consumers. devDependencies (test runners, bundlers, linters) are not -- they exist only in your own repo. peerDependencies declare a package you expect the host app to already provide (a plugin needing its framework), and the consumer installs it, not you.

Continue this lesson on YourAIZone

The full lesson has the complete explanation, worked examples, common mistakes, tests with instant checking and an AI tutor. Start right away as a guest, or create an account to keep your progress.

In the full lesson

  • The complete explanation
  • Worked examples
  • Common mistakes and how to avoid them
  • Test questions: 15
  • AI tutor that answers questions about the topic
  • Progress tracking for students, parents and teachers