Inside package.json: The Identity Card of Every Front-End Project

Every Node.js or front-end project begins with one critical file — package.json.
Think of it as your project’s identity card or Swiss Army knife:
It tells npm who you are (
name,version,license)It tells bundlers how to import you (
main,module,exports)It tells CI/CD how to build and test (
scripts.test)It tells users how to run or consume your code (
bin,scripts,dependencies)
In this article, we’ll progressively explore every important part of package.json, from a minimal, runnable file to a fully enterprise-grade configuration.
After reading, you’ll know how to:
Write a zero-error
package.jsonby handSplit dependencies and peerDependencies correctly
Make Webpack, Vite, and Node.js recognize your library simultaneously
Avoid 90% of the “It works locally but crashes after publish” issues
1. Minimum Viable Version (MVP)
Start by creating a new project and running:
npm init -y
You’ll get this default file:
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
That’s enough to:
Run your entry:
node index.jsTrigger a script:
npm test
But to make it usable, let’s clean it up:
✅ Replace license with a valid SPDX identifier (MIT, Apache-2.0, etc.)
✅ Add "private": true to prevent accidental publishing
✅ Keep only the essential fields:
{
"name": "demo",
"version": "1.0.0",
"main": "index.js",
"private": true,
"scripts": {
"start": "node index.js"
},
"license": "MIT"
}
2. The Three Pillars of Dependency Management
| Scenario | Command | Field | Example |
| Production dependencies | npm i lodash | dependencies | "lodash": "^4.17.21" |
| Development dependencies | npm i -D vite | devDependencies | "vite": "^5.0.0" |
| Host (external) dependencies | Manual | peerDependencies | "react": ">=18.0.0" |
Mnemonic:
Runs in downstream projects →
dependenciesUsed only for build/test →
devDependenciesAvoid duplicate instances →
peerDependencies
Common pitfall:peerDependencies version ranges that are too strict will break installs.
✅ Correct: "react": ">=16.8.0"
❌ Wrong: "react": "16.8.0" (exact match required)
3. Advanced Scripts — One Command to Rule Them All
A well-organized scripts section automates your entire workflow:
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"test": "vitest",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
"prepare": "husky install",
"prepublishOnly": "npm run build && npm test"
}
Lifecycle explained:
npm install→ triggersprepare→ automatically installs Husky hooksnpm publish→ triggersprepublishOnly→ ensures only built code is published
Cross-platform builds:
"build": "cross-env NODE_ENV=production tsc && vite build"
4. Making Your Library Importable: main, module, and exports
| Field | Historical Use | Ideal For | Notes |
main | CommonJS era | Legacy compatibility | Single path only |
module | Community convention | ESM bundlers | Unofficial |
exports | Node 12+ | Official, modern replacement | Supports conditions and subpaths |
A modern template looks like this:
{
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./utils": {
"types": "./dist/utils.d.ts",
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs"
}
}
}
Advantages:
Users can import subpaths directly:
import { helper } from 'your-lib/utils'Works for both ESM and CommonJS users
TypeScript hints remain accurate
5. Packaging and Publishing — Cut Bundle Size by 70%
{
"files": ["dist", "README.md", "LICENSE"],
"sideEffects": false,
"publishConfig": {
"registry": "https://registry.npmjs.org",
"access": "public"
}
}
Tips:
files: include only what should be publishedsideEffects: false: enables Webpack tree-shakingpublishConfig: set registry (e.g., private Verdaccio or Nexus for internal releases)
6. Enterprise-Level Open Source Checklist
| Step | Tool/Field | Example |
| Version compliance | SemVer | npm version patch |
| Security scan | npm audit | npm audit fix |
| Node version | engines | { "node": ">=18.0.0" } |
| License check | license | npx license-checker |
| CI publishing | GitHub Actions | npm publish |
Example CI snippet (.github/workflows/publish.yml):
- name: Publish
if: github.ref == 'refs/heads/main'
run: |
npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
npm publish
7. Visual Summary (Text Version)
package.json
├─ Meta (name, version, license, private)
├─ Dependencies (dependencies / dev / peer / optional)
├─ Scripts (scripts + lifecycle)
├─ Entry points (main → module → exports)
├─ Publishing (files, sideEffects, publishConfig)
└─ Constraints (engines, os, cpu)
8. Quick Reference: Common Errors
| Error | Cause | Fix |
Cannot find module 'xxx' | Missing dist folder | Add "files": ["dist"] |
| Multiple React versions | Wrong dependency type | Move react to peerDependencies |
npm WARN deprecated xxx | Old dependency version | npx npm-check-updates -u |
403 Forbidden on publish | Name conflict or auth issue | Change package name or npm login |
9. Conclusion
package.json might seem small, but it’s the heart of your Node.js ecosystem — driving every phase from development to deployment.
Once mastered, it helps you achieve:
Smaller bundles
Faster installs
Fewer “works on my machine” errors
Keep this checklist handy for every new project. It’ll save hours of debugging and setup time.
Happy coding!
10. Appendix — Template Repository
You can find a ready-to-use starter on GitHub:npm-lib-boilerplate-2025
It includes:
TypeScript + Vite + Vitest
GitHub Actions automated publishing
Husky + Lint-Staged for pre-commit checks
The example package.json in that repo matches every field discussed here — just clone it and start your next open-source library.





