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.