JavaScriptpackage.json Explained

package.json — Field by Field

Every Node project has a package.json at its root. It is part manifest, part build configuration, part tiny task runner. Most of the fields are optional; a few are load-bearing. This page walks the ones you will read or edit most often.

name and version

JSON
{
  "name": "my-app",
  "version": "0.1.0"
}
  • name — lowercase, no spaces, URL-safe. Required if you plan to publish. Scoped names look like @org/pkg.

  • version — Semantic Versioning string (MAJOR.MINOR.PATCH). Required if you publish.

type — CommonJS vs ES modules

The type field tells Node how to interpret .js files in this package.

JSON
{ "type": "module" }     // .js files are ES modules
{ "type": "commonjs" }   // (default) .js files are CommonJS
  • With "type": "module", .js files use import/export. Use .cjs to opt a single file back into CommonJS.

  • Without it, .js files use require/module.exports. Use .mjs to opt a single file into ESM.

The new default
Most modern toolchains assume ESM. Set `"type": "module"` in new projects unless you need to interop heavily with older CommonJS code.
main, module, exports

These three tell the world how to load your package.

  • main — the entry point for CommonJS consumers and older tooling.

  • module — historical hint for bundlers that this entry uses ES module syntax.

  • exports — the modern, authoritative map. Hides everything you don't list and lets you give different files to ESM vs CJS consumers.

A modern exports map

JSON
{
  "name": "my-lib",
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "types":  "./dist/index.d.ts"
    },
    "./utils": "./dist/utils.mjs"
  }
}

Consumers can import x from "my-lib" or import u from "my-lib/utils", but nothing else — internal files are not reachable.

scripts

A mini task runner. Each entry is a shell command. npm test, npm start and npm run <name> execute them. Special names like pre*/post* run automatically around the matching script.

JSON
{
  "scripts": {
    "dev":     "vite",
    "build":   "vite build",
    "test":    "vitest run",
    "lint":    "eslint .",
    "prebuild": "npm run lint",
    "format":  "prettier --write ."
  }
}

Inside a script, locally-installed binaries (./node_modules/.bin) are on PATH — write vite not ./node_modules/.bin/vite.

dependencies and friends

JSON
{
  "dependencies": {
    "react": "^18.2.0"
  },
  "devDependencies": {
    "vitest": "^1.0.0"
  },
  "peerDependencies": {
    "react": ">=18"
  },
  "optionalDependencies": {
    "fsevents": "^2.3.0"
  }
}
  • dependencies — installed when anyone uses your package or runs npm install in your project.

  • devDependencies — installed in your project, not when others depend on your published package.

  • peerDependencies — the package expects the host project to bring its own copy. Common in plugins.

  • optionalDependencies — install is attempted, failure is fine.

engines

Declare the Node (and npm) versions your package supports. npm install warns when the local version doesn't match; many hosting platforms read it to pick a runtime.

JSON
{
  "engines": {
    "node": ">=18.17",
    "npm":  ">=9"
  }
}
files and publishing

files is an allow-list of paths included when you publish. README.md, package.json and LICENSE are always included; node_modules and dotfiles are always excluded.

JSON
{
  "files": ["dist", "README.md"],
  "private": true
}

"private": true blocks accidental npm publish. A great default for apps that should never be published.

bin — shipping a CLI

Map a command name to a script in your package, and npm install -g will put it on the user's PATH.

JSON
{
  "name": "say-hi",
  "version": "1.0.0",
  "bin": { "hi": "./bin/cli.js" }
}
browser, sideEffects and other bundler hints
  • browser — an alternate entry for bundlers targeting browsers.

  • sideEffectsfalse tells bundlers that your modules are safe to tree-shake.

  • workspaces — an array of glob paths for monorepos.

repository, author, license

Metadata for humans and tools. The npm site renders these; CLI tools like npm repo use them to open the right page.

JSON
{
  "author": "Ada Lovelace <ada@example.com>",
  "license": "MIT",
  "repository": { "type": "git", "url": "https://github.com/me/my-lib" },
  "bugs": "https://github.com/me/my-lib/issues",
  "homepage": "https://my-lib.dev"
}
The shape of a healthy manifest
Required for an app: `name`, `scripts`, `dependencies`. Recommended: `type`, `engines`, `private: true`. For a library, add `version`, `exports`, `files`, and a `repository`.