Quiz

What are the metadata fields of a module?

Topics
JavaScript

TL;DR

For an npm package, package.json metadata describes identity (name, version), discovery and ownership (description, keywords, repository, bugs, license, author), runtime contract (type, main, exports, imports, types, files, bin, engines), dependencies, and scripts. Not every field is standardized by JavaScript itself, and package managers, Node.js, TypeScript, and bundlers consume different fields.

The most consequential fields are often exports, type, dependency categories, and files: mistakes there can break consumers or publish unintended files. Validate the packed artifact in both ESM/CommonJS environments that the package claims to support.


Example package contract

{
"name": "@example/slugify",
"version": "2.1.0",
"description": "Create URL-safe slugs",
"type": "module",
"exports": {
".": "./dist/index.js"
},
"types": "./dist/index.d.ts",
"files": ["dist", "README.md", "LICENSE"],
"engines": {
"node": ">=20"
},
"scripts": {
"build": "build-command",
"test": "test-command"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/example/slugify.git"
}
}

Identity and publishing

  • name identifies the package in a registry and in import specifiers. Scoped names use forms such as @example/slugify.
  • version is the published package version. Registries commonly require a valid semantic version, but a dependency range such as ^2.1.0 has different meaning from the package's own exact version.
  • private: true prevents accidental publication in package managers that honor it; use it for application/workspace-only packages.
  • files is an allowlist for packed content, subject to package-manager inclusion and ignore rules. Inspect the actual package tarball before publishing.

Module entry points

  • type controls how Node.js interprets .js files in that package scope: "module" for ESM or "commonjs" for CommonJS.
  • exports defines public entry points and can provide conditional targets. When present, it also encapsulates undeclared subpaths.
  • main is the legacy primary CommonJS-style entry field and remains relevant to older tools.
  • imports defines package-internal aliases beginning with # under Node.js package rules.
  • types points TypeScript-compatible tooling to the package's declaration entry.
  • bin exposes executable commands.

Supporting both ESM and CommonJS requires deliberate conditional exports and tests. Simply adding a module field is not a cross-runtime guarantee; that field is a bundler convention rather than the Node.js package contract.

Dependency fields

  • dependencies are required when consumers run the package.
  • devDependencies support development, build, and tests and are not runtime requirements of the published library.
  • peerDependencies declare a compatible host dependency that the consuming application should provide, commonly used for plugins.
  • optionalDependencies may fail to install without making the whole installation fail; runtime code must handle their absence.

Misclassifying a runtime import as a development dependency can make the packed library work in its repository but fail for consumers. Conversely, putting build tools in runtime dependencies increases consumer installation cost.

Descriptive and operational metadata

description, keywords, homepage, repository, bugs, author or contributors, funding, and license help users evaluate and maintain the package. scripts defines lifecycle and project commands; install lifecycle scripts execute code and therefore deserve supply-chain review. engines communicates supported runtimes, but enforcement depends on the package manager and its configuration.

Validation before publishing

Pack the package locally, inspect the file list, install that tarball into a clean fixture, and test every documented import path. Check that source maps do not reveal unintended source, secrets, or internal paths, and that README examples use only exported entry points.

Further reading

Exercises

Check your understanding
Beta
Check your understanding Exercise
Check your understanding Exercise

Which package.json fields can materially affect an npm package’s runtime or publication contract? Select all that apply.