Skip to content

Introduce inlinedDependencies Field in package.json #237

@sxzz

Description

@sxzz

Summary

Propose a new inlinedDependencies field in package.json as a community convention for explicitly declaring which dependencies are physically inlined into a published tarball — regardless of how they were inlined. This is a purely declarative metadata field, intended to improve ecosystem observability without instructing any package manager to change its behavior.

Background: bundleDependencies Already Exists — But Is Not Enough

npm already supports a bundleDependencies field (also accepted as bundledDependencies). When set, npm pack and npm publish will copy the listed packages from node_modules directly into the tarball.

This is the mechanism behind packages like vite shipping cac — every npm install vite delivers a copy of cac, yet cac's download count reflects none of this. cac has 20M weekly downloads, and the real number is even higher.

However, bundleDependencies has a specific and narrow semantic: "copy from node_modules at pack time." It does not cover the equally common case where a bundler (Rollup, esbuild, webpack, etc.) statically inlines dependency code at build time. Authors using a bundler pipeline cannot accurately use bundleDependencies to describe their inlined deps, because the mechanism is fundamentally different and the version actually bundled may differ from what's in node_modules.

Proposed: inlinedDependencies Field

A new inlinedDependencies field as a community standard for declaring inlined dependencies regardless of how they were inlined. The key distinction:

Field Mechanism Who sets it
bundleDependencies npm pack copies from node_modules npm (automatically honored)
inlinedDependencies (proposed) Any method: bundler tree-shaking, manual vendoring, npm pack copy, etc. Author declares explicitly

inlinedDependencies is purely declarative metadata — it does not instruct any package manager to do anything. It is a signal to tooling and registries that says: "these packages are physically present in my tarball in inlined form."

Proposed field shape (open for discussion)

Option A — string[]

{
  "inlinedDependencies": ["cac", "rollup"]
}

Simple. Exact version must be inferred from dependencies in the same manifest.

Option B — Record<string, string | string[]> (name → exact version or list of versions)

{
  "inlinedDependencies": {
    "cac": "6.7.14",
    "rollup": ["3.29.5", "4.9.1"]
  }
}

More explicit. Allows authors to record the exact version(s) bundled, which may differ from the range declared in dependencies. The value is an array to accommodate the case where a single package ends up bundled in multiple versions within the same tarball — for example, when two independent parts of a build depend on different major versions of the same library.

Both options are on the table. Community input on ergonomics and tooling compatibility is welcome.

Why Not Just Reuse bundleDependencies?

Its semantic is specifically tied to npm pack copying from node_modules. Using it to describe bundler-inlined code would be a misuse of the field and could mislead package managers and tooling that act on it today.

Open Questions

  1. Field name: inlinedDependencies? vendoredDependencies? Other suggestions welcome.
  2. Field format: string[] vs Record<string, string | string[]>? Are there other shapes worth considering?
  3. Author adoption: This field is opt-in, meaning authors can simply ignore it — leaving the ecosystem with incomplete data. Possible paths to drive adoption: proactive outreach to high-download packages known to inline deps, integration with popular bundlers to emit the field automatically from the build module graph, or tarball inspection as a fallback to detect undeclared inlined packages and prompt authors to declare them.
  4. Tooling: Should the ecosystem provide a bundler plugin or CLI to auto-generate inlinedDependencies from a build output's module graph, rather than requiring authors to maintain it by hand?

Alternatives Considered

  • Reuse bundleDependencies for all cases: already exists, but semantically wrong for bundler-inlined code and risks confusing package managers.
  • Rely on tarball inspection alone: technically possible but expensive at scale, and gives authors no explicit, intent-declaring mechanism.
  • Do nothing: leaves the ecosystem blind to a significant class of implicit dependency usage.

This is an RFC — all details are open for discussion. Also cross-posted to npmx as a potential consumer of this standard.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions