And We’re Live: Publishing My First NPM Package

March 30, 2025 by Missie Dawes

Even though literally anyone can create an NPM package, publishing one for the first time felt like a meaningful milestone. My code is out in the wild, available for anyone to see and use with a simple:

npm install @umerx/kafkajs-client

Getting the library ready for NPM was surprisingly straightforward. The real challenge came later when I tried to automate the publishing process—but more on that soon.

Developing the Library

Since I was working inside a dev container with Node.js and TypeScript already installed and my project linked to GitHub, getting started couldn’t have been easier.

To initialize the NPM package, I ran:

npm init

After following the prompts, I had a package.json file—almost ready to go. Since I was using TypeScript, I had to tweak a few properties, like updating main to point to dist/index.js instead of index.js and adding a types field.

Here’s essentially what my final package.json looked like:

{
    "name": "@umerx/kafkajs-client",
    "private": false,
    "version": "1.0.0",
    "description": "KafkaJS Wrapper",
    "main": "dist/index.js",
    "types": "dist/index.d.ts",
    "type": "module",
    "files": ["dist"],
    "scripts": {
        "build": "tsc",
    },
    "repository": {
        "type": "git",
        "url": "git+https://github.com/umerx-github/kafkajs-client.git"
    },
    "license": "ISC",
    "bugs": {
        "url": "https://github.com/umerx-github/kafkajs-client/issues"
    },
    "homepage": "https://github.com/umerx-github/kafkajs-client#readme",
    "devDependencies": {},
    "dependencies": {}
}

After some testing, the library was ready to publish!

Publishing the Package

I created a user account at npmjs.com. Since I wanted the package to live under the Umerx organization (owned by my husband), he had to add me as a member. He gave me the “admin” role, though “member” likely would have been enough for everything in this article.

Back in my dev container, I built the project:

npm run build

Then I logged into NPM:

npm login

Finally, I published the package. Since this was a scoped package (@umerx/kafkajs-client instead of just kafkajs-client), I needed to specify public access:

npm publish --access public

And that was it! The package was live.

For future updates, I simply bump the version in package.json using:

npm version <patch|minor|major>

Then I rebuild, log in, and publish again:

npm run build
npm login
npm publish --access public

Automating the Publishing Process

Even though publishing manually is simple, I wanted to automate it—partly because I have zero patience for constant 2FA prompts, but also for more practical reasons.

To enable automation, I needed an access token. At first, I tried creating one before publishing the package, but I quickly realized that wasn’t possible—I had to specify the token’s “packages and scopes,” which meant the package had to exist first.

Lesson learned: You must publish a package before you can create an access token for it.

This might seem obvious in hindsight, but the npmjs.com UI/UX initially made the relationship between access tokens, organizations, teams, and packages feel a bit unclear.

While dealing with the access token setup wasn’t the most enjoyable part of this process, the ability to automate publishing made it completely worth the mild frustration of wrestling with a clunky UI!

Closing

Looking back, publishing was easier than I expected, but automation took more effort than I anticipated because of the access token confusion. Now that automation is in place, though, pushing updates is a breeze—and I get to skip the 2FA prompts.

Worth it.