Skip to main content

Command Palette

Search for a command to run...

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

Published
5 min read
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.json by hand

  • Split 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.js

  • Trigger 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

ScenarioCommandFieldExample
Production dependenciesnpm i lodashdependencies"lodash": "^4.17.21"
Development dependenciesnpm i -D vitedevDependencies"vite": "^5.0.0"
Host (external) dependenciesManualpeerDependencies"react": ">=18.0.0"

Mnemonic:

  • Runs in downstream projects → dependencies

  • Used only for build/test → devDependencies

  • Avoid 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 → triggers prepare → automatically installs Husky hooks

  • npm publish → triggers prepublishOnly → 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

FieldHistorical UseIdeal ForNotes
mainCommonJS eraLegacy compatibilitySingle path only
moduleCommunity conventionESM bundlersUnofficial
exportsNode 12+Official, modern replacementSupports 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 published

  • sideEffects: false: enables Webpack tree-shaking

  • publishConfig: set registry (e.g., private Verdaccio or Nexus for internal releases)


6. Enterprise-Level Open Source Checklist

StepTool/FieldExample
Version complianceSemVernpm version patch
Security scannpm auditnpm audit fix
Node versionengines{ "node": ">=18.0.0" }
License checklicensenpx license-checker
CI publishingGitHub Actionsnpm 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

ErrorCauseFix
Cannot find module 'xxx'Missing dist folderAdd "files": ["dist"]
Multiple React versionsWrong dependency typeMove react to peerDependencies
npm WARN deprecated xxxOld dependency versionnpx npm-check-updates -u
403 Forbidden on publishName conflict or auth issueChange 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.