# The package.json guide

> Learn how package.json describes a Node.js project, including scripts, dependencies, module type, package entry points, engines, and semver version ranges.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2018-08-03 | Updated: 2026-07-18 | Topics: [Node.js](https://flaviocopes.com/tags/node/) | Canonical: https://flaviocopes.com/package-json/

The `package.json` file is the manifest for a Node.js project. It records project metadata, dependencies, scripts, module settings, and package entry points.

npm reads it when you install packages or run scripts. Node.js also reads fields such as `type`, `main`, `exports`, and `imports`.

The complete field reference lives in the [official npm package.json documentation](https://docs.npmjs.com/files/package.json/).

## Create a package.json file

Run this command in a new project:

```bash
npm init
```

npm asks a few questions and writes the file.

Use `-y` to accept the default values:

```bash
npm init -y
```

Applications can use a small `package.json`:

```json
{
  "name": "notes-app",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "node --watch src/server.js",
    "start": "node src/server.js",
    "test": "node --test"
  },
  "devDependencies": {
    "eslint": "^10.6.0"
  }
}
```

A package published to npm needs a `name` and `version`. A private application does not need to pretend it is a public package.

The [npm init guide](https://docs.npmjs.com/creating-a-package-json-file/) explains the interactive and default setup modes.

## package.json must be valid JSON

`package.json` uses JSON, not JavaScript.

Property names and string values need double quotes. Comments and trailing commas are not valid:

```json
{
  "name": "notes-app",
  "private": true
}
```

## name and version

The `name` identifies a package:

```json
{
  "name": "string-tools"
}
```

Scoped package names start with an organization or username:

```json
{
  "name": "@flaviocopes/string-tools"
}
```

The `version` identifies a release:

```json
{
  "version": "2.1.0"
}
```

Published packages need both fields. Together they identify one exact package release.

## description, keywords, and license

These fields help people understand a published package:

```json
{
  "description": "Small string utilities for Node.js",
  "keywords": ["strings", "utilities"],
  "license": "MIT"
}
```

Use a valid SPDX license identifier such as `MIT`, `ISC`, or `Apache-2.0`.

## author and contributors

The author can be a string:

```json
{
  "author": "Flavio Copes <your@email.com> (https://flaviocopes.com)"
}
```

Or an object:

```json
{
  "author": {
    "name": "Flavio Copes",
    "email": "your@email.com",
    "url": "https://flaviocopes.com"
  }
}
```

Use `contributors` for additional people:

```json
{
  "contributors": [
    {
      "name": "Roger"
    },
    {
      "name": "Syd"
    }
  ]
}
```

## homepage, bugs, and repository

These fields connect a published package to its documentation and source code:

```json
{
  "homepage": "https://github.com/flaviocopes/flaviocopes.com#readme",
  "bugs": {
    "url": "https://github.com/flaviocopes/flaviocopes.com/issues"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/flaviocopes/flaviocopes.com.git"
  }
}
```

If a package lives inside a monorepo, `repository.directory` can point to its subfolder.

## private

Set `private` to `true` for an application or package that must not be published:

```json
{
  "private": true
}
```

npm refuses to publish a package marked private. This protects against accidental publication.

## scripts

Scripts give your project memorable commands:

```json
{
  "scripts": {
    "dev": "node --watch src/server.js",
    "start": "node src/server.js",
    "test": "node --test",
    "lint": "eslint ."
  }
}
```

Run a custom script with:

```bash
npm run dev
```

`start` and `test` have shorter forms:

```bash
npm start
npm test
```

You can pass arguments to the underlying command after `--`:

```bash
npm test -- --test-name-pattern="user login"
```

The [npm scripts documentation](https://docs.npmjs.com/cli/v11/using-npm/scripts/) covers lifecycle scripts and the environment available to commands.

## dependencies

`dependencies` lists packages required when the application runs.

This command adds a dependency:

```bash
npm install fastify
```

npm saves regular installs to `dependencies` by default and records the selected version range.

## devDependencies

`devDependencies` contains tools needed to develop, test, or build the project:

```json
{
  "devDependencies": {
    "eslint": "^10.6.0",
    "prettier": "3.9.5"
  }
}
```

Add one with:

```bash
npm install --save-dev eslint
```

A normal `npm install` installs both dependency groups. Production installs can omit development dependencies with `npm install --omit=dev`.

The [official npm dependency guide](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file/) explains when to use each field.

## type

The `type` field tells Node.js how to interpret `.js` files:

```json
{
  "type": "module"
}
```

With `"type": "module"`, `.js` files use ES Modules. With `"type": "commonjs"`, they use CommonJS.

The explicit `.mjs` and `.cjs` extensions always select ES Modules and CommonJS respectively.

Node recommends being explicit about `type`, especially for published packages. See the [Node.js module system rules](https://nodejs.org/api/packages.html#determining-module-system).

## main and exports

`main` is the traditional package entry point:

```json
{
  "main": "./dist/index.js"
}
```

`exports` is the modern way to define a package's public entry points:

```json
{
  "exports": {
    ".": "./dist/index.js",
    "./format": "./dist/format.js"
  }
}
```

When `exports` is present, package users cannot import unlisted internal paths. This lets package authors define a clear public API.

Conditional exports can provide different files to `import` and `require`, but test that setup carefully. The [Node.js package entry points guide](https://nodejs.org/api/packages.html#package-entry-points) explains the available patterns.

## engines

The `engines` field documents supported runtime versions:

```json
{
  "engines": {
    "node": ">=22"
  }
}
```

npm usually treats incompatible engines as a warning unless `engine-strict` is enabled. Do not rely on this field as the only runtime check.

## files

For a published package, `files` controls what npm includes:

```json
{
  "files": [
    "dist",
    "README.md"
  ]
}
```

Some files, including `package.json`, `README`, and the license, are always included. Test the final package before publishing:

```bash
npm pack --dry-run
```

## workspaces

Workspaces let one root project manage several related packages:

```json
{
  "private": true,
  "workspaces": [
    "packages/*"
  ]
}
```

npm links workspace packages during installation and can run commands in one or all workspaces. See the [official npm workspaces guide](https://docs.npmjs.com/cli/v11/using-npm/workspaces/).

## Package version ranges

Dependencies use semantic version ranges:

```json
{
  "dependencies": {
    "first-package": "2.3.1",
    "second-package": "~2.3.1",
    "third-package": "^2.3.1"
  }
}
```

The common rules are:

- `2.3.1` accepts only version `2.3.1`
- `~2.3.1` accepts patch updates below `2.4.0`
- `^2.3.1` accepts compatible updates below `3.0.0`
- `>=2.3.1 <3` defines an explicit range

Caret ranges behave differently before version `1.0.0`. For example, `^0.13.0` stays below `0.14.0`.

Use the [npm semantic versioning guide](https://docs.npmjs.com/about-semantic-versioning/) when a range is not obvious.

`package-lock.json` records the exact resolved dependency tree. Commit it for applications so other developers and CI can reproduce the same install.
