1. Introduction
In this guide, I’ll walk you through the entire process of creating and publishing your first NPM package — from setting up your project, writing the code, and testing it locally, to pushing it live on the NPM registry. Whether you’re building a small utility or planning a larger open-source project, this article will give you a solid starting point.
Creating your own NPM package allows you to:
- Reuse your code across multiple projects.
- Share useful tools with the dev community.
- Build a portfolio and get recognised for your work.
2. Prerequisites
Basic knowledge of JavaScript/TypeScript.
Node.js and npm installed.
An npm account.
3. Setting Up Your Project
mkdir my-awesome-package
cd my-awesome-package
npm init -y
4. Writing Your Package Code
Create an index.js or index.ts file.
my-awesome-package/
├── src/
│ └── index.js (or index.ts)
├── package.json
└── README.md
/**
* Capitalizes the first letter of a string
* @param {string} str - The string to capitalize
* @returns {string} The capitalized string
*/
function capitalize(str) {
if (typeof str !== 'string') {
throw new TypeError('Expected a string');
}
return str.charAt(0).toUpperCase() + str.slice(1);
}
module.exports = capitalize;
{
"name": "my-awesome-package",
"version": "1.0.0",
"main": "src/index.js",
...
}
5. Testing Locally
How to test your package locally in another project using npm link.
Before publishing your package to the world, you’ll want to test it in a real-world environment — like another project that uses your package.
That’s where npm link
comes in.
cd ~/projects/my-awesome-package
npm link
This makes your local package globally available (as if it was published).
You’ll see a message like:
/Users/you/.nvm/versions/node/v18.0.0/lib/node_modules/my-awesome-package -> /Users/you/projects/my-awesome-package
go to the test project:
cd ~/projects/test-app
npm link my-awesome-package
In your test project, you can now import your package like this:
// test-app/index.js
const capitalize = require('my-awesome-package');
console.log(capitalize("linked!")); // Output: "Linked!"
6. Adding README.md
Your code may be brilliant — but if no one knows what it does or how to use it, it won’t go far.
That’s why a clear, concise, and helpful README.md is essential.
Here’s a simple but effective layout for your README.md:
My Awesome Package
`Short description
🚀 Installation
How to install the package
🧠 Usage
Examples of how to use it
🛠 API
Function definitions (inputs/outputs)
📦 License`
Open source license info (MIT, ISC, etc.)
Tools You Can Use:
Markdown preview plugins in VS Code to check how it looks
7. Ignoring Unwanted Files
When you publish an NPM package, you want to keep it clean, small, and relevant. That means:
✅ Include only what's necessary for users.
❌ Exclude dev files, tests, local configs, build tools, etc.
.gitignore:Prevents files from being tracked in Git
.npmignore:Prevents files from being included in your NPM package
Example: .gitignore
# Node modules
node_modules/
# Build output
dist/
build/
# Logs
*.log
# IDE/editor files
.vscode/
.idea/
# Environment
.env
Example: .npmignore
# Don't publish source files or configs
src/
tests/
__tests__/
coverage/
.eslintrc.json
.prettierrc
tsconfig.json
.vitest.config.ts
.vscode/
.env
# Ignore lockfiles
package-lock.json
yarn.lock
# Ignore other dev tools
*.log
Generally, you only want to include:
dist/
README.md
LICENSE
package.json
index.js (or main entry)
types/ (if TypeScript types are generated)
8. Publishing to NPM
Step 1: Create an NPM Account (if you haven't)
npm login
It will ask for:
your username
your password
your email
Once logged in successfully, your credentials are saved and you're ready to publish!
Step 2: Check your package.json
Make sure the essential fields are filled correctly:
{
"name": "your-package-name", // must be unique!
"version": "1.0.0",
"description": "A simple utility that does X",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "vitest"
},
"repository": {
"type": "git",
"url": "git+https://github.com/your-username/your-repo.git"
},
"keywords": ["utility", "npm", "typescript"],
"author": "Your Name",
"license": "MIT"
}
👉 Don't forget to make sure the package name is unique!
Step 3: Build Before Publishing
If you're using TypeScript or need a build step, make sure everything is compiled first:
npm run build
Step 4: Preview What Will Be Published
npm pack --dry-run
It will show which files will be included in your package. Example output:
npm notice 📦 [email protected]
npm notice === Tarball Contents ===
npm notice 1.1kB package.json
npm notice 3.4kB dist/index.js
npm notice 1.2kB README.md
npm notice === Tarball Details ===
Step 5: Publish It!
npm publish
And that's it - your package is live!
9. Versioning Your Package
When you're maintaining an NPM package, versioning is critical. It helps developers (including your future self) understand how updates might affect existing projects that use your package.
What is Semantic Versioning?
NPM follows Semantic Versioning - usually written like this:
MAJOR.MINOR.PATCH
Each part has a specific meaning:
MAJOR: Breaking changes - the API has changed in a way that may not be backward compatible.
MINOR: New features added in a backward-compatible manner.
PATCH: Bug fixes or small updates that don't break anything.
npm version patch # bumps 1.0.0 → 1.0.1
npm version minor # bumps 1.0.1 → 1.1.0
npm version major # bumps 1.1.0 → 2.0.0
If you found this helpful, feel free to share it with others, drop a comment, or follow me for more dev content!
Happy coding 👨💻👩💻