Building and Publishing an NPM Package with AI
A complete guide to creating, testing, and publishing your first NPM package using AI-assisted development.
Building and Publishing an NPM Package with AI
Publishing an NPM package takes your vibecoding skills beyond web apps into the open-source ecosystem. Here's how to do it properly.
Why Publish a Package?
- Share reusable code across your own projects
- Contribute to open source and build your reputation
- Learn deeper fundamentals — packages have stricter requirements than apps
- Help other developers solve problems you've already solved
Step 1: Choose What to Build
Good first packages are:
- Utility functions you keep copying between projects
- React hooks that solve a common problem
- CLI tools that automate a repetitive task
- Wrappers around APIs that simplify the interface
Bad first packages:
- Anything that already exists and is well-maintained
- Extremely niche tools only you would use
- Anything requiring complex build pipelines
Step 2: Set Up the Project
mkdir my-package && cd my-package
npm init -y
Prompt the AI:
"Set up a TypeScript NPM package project with:
- TypeScript compilation to both ESM and CJS
- tsconfig.json configured for a library (not an app)
- package.json with proper main, module, types, and exports fields
- A src/ directory with an index.ts entry point
- Jest for testing
- A .gitignore and .npmignore"
Key package.json Fields
{
"name": "my-package",
"version": "0.1.0",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
},
"files": ["dist"],
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"test": "jest",
"prepublishOnly": "npm run build && npm test"
}
}
Install tsup for zero-config TypeScript bundling:
npm install -D tsup typescript jest @types/jest ts-jest
Step 3: Write Your Code
Structure your source in src/:
src/
index.ts # Public API (exports)
utils.ts # Internal utilities
types.ts # TypeScript types
The Golden Rule
Your index.ts should only export what users need:
// src/index.ts
export { formatDate } from "./format-date";
export { parseDate } from "./parse-date";
export type { DateFormatOptions } from "./types";
Keep internal helpers unexported. Every export is a public API commitment.
Step 4: Write Tests
This is where AI shines. Prompt:
"Write comprehensive Jest tests for this function. Include: happy path, edge cases, error cases, and type checking. Use TypeScript."
Then paste your function. Use our Test Generator for this.
Test Structure
describe("formatDate", () => {
it("formats a date with default options", () => {
expect(formatDate(new Date("2026-03-15"))).toBe("March 15, 2026");
});
it("handles custom format", () => {
expect(formatDate(new Date("2026-03-15"), { format: "short" })).toBe("3/15/26");
});
it("throws on invalid date", () => {
expect(() => formatDate(new Date("invalid"))).toThrow("Invalid date");
});
});
Step 5: Document It
Create a README.md with:
- What it does — one paragraph
- Installation —
npm install my-package - Quick start — minimal working example
- API reference — every exported function with parameters and return types
- Examples — 2-3 real-world usage scenarios
Use our README Generator to get a starting draft.
Step 6: Publish
First Time Setup
# Create an NPM account (if you don't have one)
npm adduser
# Login
npm login
Publish
# Dry run first — see what will be published
npm pack --dry-run
# Publish
npm publish
For Scoped Packages
If your package name starts with @yourname/:
npm publish --access public
Step 7: Maintain It
Publishing is the beginning, not the end:
- Semantic versioning: patch (1.0.1) for fixes, minor (1.1.0) for features, major (2.0.0) for breaking changes
- Changelog: document what changed in each version
- Issues: respond to bug reports within a week
- Dependencies: keep them updated
Common AI Mistakes in Package Code
-
App-specific code — AI generates code that assumes Next.js, React, or a browser environment. Packages should be environment-agnostic unless specifically designed for a platform.
-
Missing TypeScript exports — the
typesfield in package.json must point to generated.d.tsfiles. -
Side effects on import — packages shouldn't do anything when imported (no console.logs, no API calls, no DOM manipulation).
-
Heavy dependencies — AI adds
lodash,moment, or other large libraries. For a package, every dependency is your user's dependency. Minimize them. -
No input validation — packages are used by strangers. Validate inputs and throw helpful error messages.
Checklist Before Publishing
- [ ] TypeScript compiles without errors
- [ ] All tests pass
- [ ] Package exports are correct (test with
npm pack+ install in a test project) - [ ] README includes installation, usage, and API docs
- [ ]
filesfield in package.json only includesdist/ - [ ] No secrets, test fixtures, or unnecessary files in the package
- [ ] License file is present
- [ ] Version follows semver
Your first package doesn't need to be revolutionary. It just needs to work, be well-documented, and solve a real problem. Ship it.
Stay in the flow
Get vibecoding tips, new tool announcements, and guides delivered to your inbox.
No spam, unsubscribe anytime.