> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# @aspect_rules_js//npm:extensions.bzl

> Bazel rules_js bzlmod extensions including npm_translate_lock and npm_import for resolving pnpm lockfiles and fetching npm packages in MODULE.bazel.

<Callout icon="book">
  Documentation for [@aspect\_rules\_js@v3.0.3](https://registry.bazel.build/modules/aspect_rules_js/3.0.3) -- <Icon icon="github" iconType="brands" /> [View source](https://github.com/aspect-build/rules_js/blob/v3.0.3/npm/extensions.bzl)
</Callout>

Setup steps, or [extensions](https://bazel.build/docs/bzlmod#extension-definition) for pnpm.

These are used in `MODULE.bazel` files to pin tooling versions, for example assuming

* the desired version of Node.js is specified in a `.nvmrc` file
* the desired version of pnpm is specified in the `package.json#packageManager` field
* package manager preferences (especially `hoist=false`) is in `.npmrc`
* pnpm dependencies were resolved and locked using `pnpm-lock.yaml`

then the following `MODULE.bazel` file can be used:

```python theme={null}
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
node.toolchain(node_version_from_nvmrc = "//:.nvmrc")
use_repo(node, "nodejs_toolchains")

pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
use_repo(pnpm, "pnpm")
pnpm.pnpm(pnpm_version_from = "//:package.json")

npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm")
npm.npm_translate_lock(
    name = "npm",
    npmrc = "//:.npmrc",
    pnpm_lock = "//:pnpm-lock.yaml",
)
use_repo(npm, "npm")
```

## Module extension: `npm`

### Tag: `npm_translate_lock`

Import a pnpm lock file and create `npm_import` rules to fetch each package.

These use Bazel's downloader to fetch the packages.
You can use this to redirect all fetches through a store like Artifactory.

See [Configuring Bazel's Downloader](/blog/configuring-bazels-downloader)
for more info about how it works and how to configure it.

The [`npm_translate_lock`](#npm_translate_lock) module extension tag is the primary user-facing API.
It uses the lockfile format from [pnpm](https://pnpm.io/motivation) because it gives us reliable
semantics for how to dynamically lay out `node_modules` trees on disk in bazel-out.

To create `pnpm-lock.yaml`, consider using [`pnpm import`](https://pnpm.io/cli/import)
to preserve the versions pinned by your existing `package-lock.json` or `yarn.lock` file.

If you don't have an existing lock file, you can run `npx pnpm install --lockfile-only`.

Advanced users may want to directly fetch a package from npm rather than start from a lockfile,
[`npm_import`](#tag-npm_import) does this.

### Generated repository layout

* A `defs.bzl` file containing some rules such as `npm_link_all_packages`, which are [documented here](https://github.com/aspect-build/rules_js/blob/main/docs/README.md#npm_link_all_packages).
* `BUILD` files declaring targets for the packages listed as `dependencies` or `devDependencies` in `package.json`,
  so you can declare dependencies on those packages without having to repeat version information.

This macro creates a `pnpm` external repository, if the user didn't create a repository named
"pnpm" prior to calling `npm_translate_lock`.
`rules_js` currently only uses this repository when `npm_package_lock` or `yarn_lock` are used.
Set `pnpm_version` to `None` to inhibit this repository creation.

For more about how to use npm\_translate\_lock, read [pnpm and rules\_js](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md).

<ParamField body="bins" type="dictionary: String → List of strings" default={`{}`}>
  Binary files to create in `node_modules/.bin` for packages in this lock file.

  For a given package, this is typically derived from the "bin" attribute in
  the package.json file of that package.

  For example:

  ```
  bins = {
      "@foo/bar": {
          "foo": "./foo.js",
          "bar": "./bar.js"
      },
  }
  ```

  Dicts of bins not additive. The most specific match wins.

  In the future, this field may be automatically populated from information in the pnpm lock
  file. That feature is currently blocked on [https://github.com/pnpm/pnpm/issues/5131](https://github.com/pnpm/pnpm/issues/5131).

  Note: Bzlmod users must use an alternative syntax due to module extensions not supporting
  dict-of-dict attributes:

  ```
  bins = {
      "@foo/bar": [
          "foo=./foo.js",
          "bar=./bar.js"
      ],
  }
  ```
</ParamField>

<ParamField body="custom_postinstalls" type="dictionary: String → String" default={`{}`}>
  "
  A map of package names or package names with their version (e.g., "my-package" or "my-package\@v1.2.3")
  to a custom postinstall script to apply to the downloaded npm package after its lifecycle scripts runs.
  If the version is left out of the package name, the script will run on every version of the npm package. If
  a custom postinstall scripts exists for a package as well as for a specific version, the script for the versioned package
  will be appended with `&&` to the non-versioned package script.

  For example,

  ```
  custom_postinstalls = {
      "@foo/bar": "echo something > somewhere.txt",
      "fum@0.0.1": "echo something_else > somewhere_else.txt",
  },
  ```

  Custom postinstalls are additive and joined with `&&` when there are multiple matches for a package.
  More specific matches are appended to previous matches.
</ParamField>

<ParamField body="data" type="list of labels" default={`[]`}>
  Data files required by this repository rule when auto-updating the pnpm lock file.

  Only needed when `update_pnpm_lock` is True.
  Read more: [using update\_pnpm\_lock](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#update_pnpm_lock)
</ParamField>

<ParamField body="external_repository_action_cache" type="string" default={`.aspect/rules/external_repository_action_cache`}>
  The location of the external repository action cache to write to when `update_pnpm_lock` = True.
</ParamField>

<ParamField body="generate_bzl_library_targets" type="boolean" default={`False`} />

<ParamField body="lifecycle_hooks_envs" type="dictionary: String → List of strings" default={`{}`}>
  Environment variables set for the lifecycle hooks actions on npm packages.
  The environment variables can be defined per package by package name or globally using "\*".
  Variables are declared as key/value pairs of the form "key=value".
  Multiple matches are additive.

  Read more: [lifecycles](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#lifecycles)
</ParamField>

<ParamField body="lifecycle_hooks" type="dictionary: String → List of strings" default={`{}`}>
  A dict of package names to list of lifecycle hooks to run for that package.

  By default the `preinstall`, `install` and `postinstall` hooks are run if they exist. This attribute allows
  the default to be overridden for packages to run `prepare`.

  List of hooks are not additive. The most specific match wins.

  Read more: [lifecycles](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#lifecycles)
</ParamField>

<ParamField body="lifecycle_hooks_exclude" type="list of strings" default={`[]`}>
  A list of package names or package names with their version (e.g., "my-package" or "my-package\@v1.2.3")
  to not run any lifecycle hooks on.

  Equivalent to adding `<value>: []` to `lifecycle_hooks`.

  Read more: [lifecycles](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#lifecycles)
</ParamField>

<ParamField body="lifecycle_hooks_execution_requirements" type="dictionary: String → List of strings" default={`{}`}>
  Execution requirements applied to the preinstall, install and postinstall
  lifecycle hooks on npm packages.

  The execution requirements can be defined per package by package name or globally using "\*".

  Execution requirements are not additive. The most specific match wins.

  Read more: [lifecycles](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#lifecycles)
</ParamField>

<ParamField body="lifecycle_hooks_use_default_shell_env" type="dictionary: String → String" default={`{}`}>
  The `use_default_shell_env` attribute of the lifecycle hooks
  actions on npm packages.

  See [use\_default\_shell\_env](https://bazel.build/rules/lib/builtins/actions#run.use_default_shell_env)

  This defaults to False to reduce the negative effects of `use_default_shell_env`.

  Read more: [lifecycles](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#lifecycles)
</ParamField>

<ParamField body="lifecycle_hooks_no_sandbox" type="boolean" default={`True`}>
  If True, a "no-sandbox" execution requirement is added to all lifecycle hooks
  unless overridden by `lifecycle_hooks_execution_requirements`.

  Equivalent to adding `"*": ["no-sandbox"]` to `lifecycle_hooks_execution_requirements`.

  This defaults to True to limit the overhead of sandbox creation and copying the output
  TreeArtifacts out of the sandbox.

  Read more: [lifecycles](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#lifecycles)
</ParamField>

<ParamField body="name" type="name" default={`""`} />

<ParamField body="no_dev" type="boolean" default={`False`}>
  If True, `devDependencies` are not included
</ParamField>

<ParamField body="no_optional" type="boolean" default={`False`}>
  If True, `optionalDependencies` are not installed.

  Currently `npm_translate_lock` behaves differently from pnpm in that it downloads all `optionalDependencies`
  while pnpm doesn't download `optionalDependencies` that are not needed for the platform pnpm is run on.
  See [https://github.com/pnpm/pnpm/pull/3672](https://github.com/pnpm/pnpm/pull/3672) for more context.
</ParamField>

<ParamField body="node_toolchain_prefix" type="string" default={`nodejs`}>
  the prefix of the node toolchain to use when generating the pnpm lockfile.
</ParamField>

<ParamField body="npm_package_lock" type="label" default={`None`}>
  The `package-lock.json` file written by `npm install`.

  Only one of `npm_package_lock` or `yarn_lock` may be set.
</ParamField>

<ParamField body="npm_package_target_name" type="string" default={`pkg`}>
  The name of linked `js_library`, `npm_package` or `JsInfo` producing targets.

  When targets are linked as pnpm workspace packages, the name of the target must align with this value.

  The `{dirname}` placeholder is replaced with the directory name of the target.
</ParamField>

<ParamField body="npmrc" type="label" default={`None`}>
  The `.npmrc` file, if any, to use.

  When set, the `.npmrc` file specified is parsed and npm auth tokens and basic authentication configuration
  specified in the file are passed to the Bazel downloader for authentication with private npm registries.

  In a future release, pnpm settings such as public-hoist-patterns will be used.
</ParamField>

<ParamField body="package_visibility" type="dictionary: String → List of strings" default={`{}`}>
  A map of package names or package names with their version (e.g., "my-package" or "my-package\@v1.2.3")
  to a visibility list to use for the package's generated node\_modules link targets. Multiple matches are additive.
  If there are no matches then the package's generated node\_modules link targets default to public visibility
  (`["//visibility:public"]`).
</ParamField>

<ParamField body="patch_tool" type="label" default={`None`}>
  The patch tool to use. If not specified, the `patch` from `PATH` is used.
</ParamField>

<ParamField body="patch_args" type="dictionary: String → List of strings" default={`{"*": ["-p0"]}`}>
  A map of package names or package names with their version (e.g., "my-package" or "my-package\@v1.2.3")
  to a label list arguments to pass to the patch tool. The most specific match wins.

  Read more: [patching](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#patching)
</ParamField>

<ParamField body="patches" type="dictionary: String → List of strings" default={`{}`}>
  A map of package names or package names with their version (e.g., "my-package" or "my-package\@v1.2.3")
  to a label list of patches to apply to the downloaded npm package. Multiple matches are additive.

  These patches are applied after any patches in [pnpm.patchedDependencies](https://pnpm.io/next/package_json#pnpmpatcheddependencies).

  Read more: [patching](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#patching)
</ParamField>

<ParamField body="use_pnpm" type="label" default={`@pnpm//:package/bin/pnpm.cjs`}>
  label of the pnpm entry point to use.
</ParamField>

<ParamField body="pnpm_lock" type="label" default={`None`}>
  The `pnpm-lock.yaml` file, containing resolved and pinned package versions.
</ParamField>

<ParamField body="preupdate" type="list of labels" default={`[]`}>
  Node.js scripts to run in this repository rule before auto-updating the pnpm lock file.

  Scripts are run sequentially in the order they are listed. The working directory is set to the root of the
  external repository. Make sure all files required by preupdate scripts are added to the `data` attribute.

  A preupdate script could, for example, transform `resolutions` in the root `package.json` file from a format
  that yarn understands such as `@foo/**/bar` to the equivalent `@foo/*>bar` that pnpm understands so that
  `resolutions` are compatible with pnpm when running `pnpm import` to update the pnpm lock file.

  Only needed when `update_pnpm_lock` is True.
  Read more: [using update\_pnpm\_lock](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#update_pnpm_lock)
</ParamField>

<ParamField body="public_hoist_packages" type="dictionary: String → List of strings" default={`{}`}>
  A map of package names or package names with their version (e.g., "my-package" or "my-package\@v1.2.3")
  to a list of Bazel packages in which to hoist the package to the top-level of the node\_modules tree when linking.

  This is similar to setting [https://pnpm.io/npmrc#public-hoist-pattern](https://pnpm.io/npmrc#public-hoist-pattern) in an .npmrc file outside of Bazel, however,
  wild-cards are not yet supported and npm\_translate\_lock will fail if there are multiple versions of a package that
  are to be hoisted.

  ```
  public_hoist_packages = {
      "@foo/bar": [""] # link to the root package
      "fum@0.0.1": ["some/sub/package"]
  },
  ```

  List of public hoist packages are additive when there are multiple matches for a package. More specific matches
  are appended to previous matches.
</ParamField>

<ParamField body="quiet" type="boolean" default={`True`}>
  Set to False to print info logs and output stdout & stderr of pnpm lock update actions to the console.
</ParamField>

<ParamField body="run_lifecycle_hooks" type="boolean" default={`True`}>
  Sets a default value for `lifecycle_hooks` if `*` not already set.
  Set this to `False` to disable lifecycle hooks.
</ParamField>

<ParamField body="update_pnpm_lock" type="boolean" default={`False`}>
  When True, the pnpm lock file will be updated automatically when any of its inputs
  have changed since the last update.

  Defaults to True when one of `npm_package_lock` or `yarn_lock` are set.
  Otherwise it defaults to False.

  Read more: [using update\_pnpm\_lock](https://github.com/aspect-build/rules_js/blob/main/docs/pnpm.md#update_pnpm_lock)
</ParamField>

<ParamField body="use_home_npmrc" type="boolean" default={`False`}>
  Use the `$HOME/.npmrc` file (or `$USERPROFILE/.npmrc` when on Windows) if it exists.

  Settings from home `.npmrc` are merged with settings loaded from the `.npmrc` file specified
  in the `npmrc` attribute, if any. Where there are conflicting settings, the home `.npmrc` values
  will take precedence.

  WARNING: The repository rule will not be invalidated by changes to the home `.npmrc` file since there
  is no way to specify this file as an input to the repository rule. If changes are made to the home
  `.npmrc` you can force the repository rule to re-run and pick up the changes by running:
  `bazel run @{name}//:sync` where `name` is the name of the `npm_translate_lock` you want to re-run.

  Because of the repository rule invalidation issue, using the home `.npmrc` is not recommended.
  `.npmrc` settings should generally go in the `npmrc` in your repository so they are shared by all
  developers. The home `.npmrc` should be reserved for authentication settings for private npm repositories.
</ParamField>

<ParamField body="verify_node_modules_ignored" type="label" default={`None`}>
  **Bazel 7.x only (deprecated)** - Verifies node\_modules folders are ignored.

  This points to a `.bazelignore` file to verify that all nested node\_modules directories
  pnpm will create are listed.

  **Bazel 8+**: Use `ignore_directories(["**/node_modules"])` in REPO.bazel instead.

  See [https://github.com/bazelbuild/bazel/issues/8106](https://github.com/bazelbuild/bazel/issues/8106)
</ParamField>

<ParamField body="verify_patches" type="label" default={`None`}>
  Label to a patch list file.

  Use this together with the `list_patches` macro to guarantee that all patches in a patch folder
  are included in the `patches` attribute.

  For example:

  ```
  verify_patches = "//patches:patches.list",
  ```

  In your patches folder add a BUILD.bazel file containing.

  ```
  load("@aspect_rules_js//npm:repositories.bzl", "list_patches")

  list_patches(
      name = "patches",
      out = "patches.list",
  )
  ```

  Once you have created this file, you need to create an empty `patches.list` file before generating the first list. You can do this by running

  ```
  touch patches/patches.list
  ```

  Finally, write the patches file at least once to make sure all patches are listed. This can be done by running `bazel run //patches:patches_update`.

  See the `list_patches` documentation for further info.
  NOTE: if you would like to customize the patches directory location, you can set a flag in the `.npmrc`. Here is an example of what this might look like

  ```
  # Set the directory for pnpm when patching
  # https://github.com/pnpm/pnpm/issues/6508#issuecomment-1537242124
  patches-dir=bazel/js/patches
  ```

  If you do this, you will have to update the `verify_patches` path to be this path instead of `//patches` like above.
</ParamField>

<ParamField body="yarn_lock" type="label" default={`None`}>
  The `yarn.lock` file written by `yarn install`.

  Only one of `npm_package_lock` or `yarn_lock` may be set.
</ParamField>

### Tag: `npm_import`

Import a single npm package into Bazel.

Normally you'd want to use `npm_translate_lock` to import all your packages at once.
It generates `npm_import` rules.
You can create these manually if you want to have exact control.

Bazel will only fetch the given package from an external registry if the package is
required for the user-requested targets to be build/tested.

For example, in `MODULE.bazel`:

```python theme={null}
npm.npm_import(
    name = "npm__at_types_node__15.12.2",
    package = "@types/node",
    version = "15.12.2",
    integrity = "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==",
)
use_repo(npm, "npm__at_types_node__15.12.2")
use_repo(npm, "npm__at_types_node__15.12.2__links")
```

> This is similar to Bazel rules in other ecosystems named "\_import" like
> `apple_bundle_import`, `scala_import`, `java_import`, and `py_import`.
> `go_repository` is also a model for this rule.

The name of this repository should contain the version number, so that multiple versions of the same
package don't collide.
(Note that the npm ecosystem always supports multiple versions of a library depending on where
it is required, unlike other languages like Go or Python.)

To consume the downloaded package in rules, it must be "linked" into the link package in the
package's `BUILD.bazel` file:

```
load("@npm__at_types_node__15.12.2__links//:defs.bzl", npm_link_types_node = "npm_link_imported_package")

npm_link_types_node()
```

This links `@types/node` into the `node_modules` of this package with the target name `:node_modules/@types/node`.

A `:node_modules/@types/node/dir` filegroup target is also created that provides the directory artifact of the npm package.
These targets can be used to create entry points for binary target or to access files within the npm package.

NB: You can choose any target name for the link target but we recommend using the `node_modules/@scope/name` and
`node_modules/name` convention for readability.

When using `npm_translate_lock`, you can link all the npm dependencies in the lock file for a package:

```
load("@npm//:defs.bzl", "npm_link_all_packages")

npm_link_all_packages()
```

This creates `:node_modules/name` and `:node_modules/@scope/name` targets for all direct npm dependencies in the package.
It also creates `:node_modules/name/dir` and `:node_modules/@scope/name/dir` filegroup targets that provide the directory artifacts of their npm packages.
These targets can be used to create entry points for binary targets or to access files within the npm package.

If you have a mix of `npm_link_all_packages` and `npm_link_imported_package` functions to call you can pass the
`npm_link_imported_package` link functions to the `imported_links` attribute of `npm_link_all_packages` to link
them all in one call. For example,

```
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@npm__at_types_node__15.12.2__links//:defs.bzl", npm_link_types_node = "npm_link_imported_package")

npm_link_all_packages(
    imported_links = [
        npm_link_types_node,
    ]
)
```

This has the added benefit of adding the `imported_links` to the convenience `:node_modules` target which
includes all direct dependencies in that package.

NB: You can pass an name to npm\_link\_all\_packages and this will change the targets generated to "`{name}`/@scope/name" and
"`{name}`/name". We recommend using "node\_modules" as the convention for readability.

To change the proxy URL we use to fetch, configure the Bazel downloader:

1. Make a file containing a rewrite rule like

   `rewrite (registry.npmjs.org)/(.*) artifactory.build.internal.net/artifactory/$1/$2`

2. To understand the rewrites, see [UrlRewriterConfig] in Bazel sources.

3. Point bazel to the config with a line in .bazelrc like
   common --experimental\_downloader\_config=.bazel\_downloader\_config

Read more: [Configuring Bazel's Downloader](/blog/configuring-bazels-downloader).

[UrlRewriterConfig]: https://github.com/bazelbuild/bazel/blob/4.2.1/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/UrlRewriterConfig.java#L66

<ParamField body="package" type="string" required>
  Name of the npm package, such as `acorn` or `@types/node`
</ParamField>

<ParamField body="root_package" type="string" default={`""`}>
  The root package where the node\_modules package store is linked to.
  Typically this is the package that the pnpm-lock.yaml file is located when using `npm_translate_lock`.
</ParamField>

<ParamField body="version" type="string" required>
  Version of the npm package, such as `8.4.0`
</ParamField>

<ParamField body="exclude_package_contents" type="list of strings" default={`[]`}>
  List of glob patterns to exclude from the linked package.

  This is useful for excluding files that are not needed in the linked package.

  For example:

  ```
  exclude_package_contents = ["**/tests/**"]
  ```
</ParamField>

<ParamField body="exclude_package_contents_presets" type="list of strings" default={`["basic"]`} />

<ParamField body="commit" type="string" default={`""`}>
  Specific commit to be checked out if url is a git repository.
</ParamField>

<ParamField body="custom_postinstall" type="string" default={`""`}>
  Custom string postinstall script to run on the installed npm package.

  Runs after any existing lifecycle hooks if any are enabled.
</ParamField>

<ParamField body="extra_build_content" type="string" default={`""`}>
  Additional content to append on the generated BUILD file at the root of
  the created repository, either as a string or a list of lines to concatenate.
</ParamField>

<ParamField body="extract_full_archive" type="boolean" default={`False`} />

<ParamField body="integrity" type="string" default={`""`}>
  Expected checksum of the file downloaded, in Subresource Integrity format.
  This must match the checksum of the file downloaded.

  This is the same as appears in the pnpm-lock.yaml, yarn.lock or package-lock.json file.

  It is a security risk to omit the checksum as remote files can change.

  At best omitting this field will make your build non-hermetic.

  It is optional to make development easier but should be set before shipping.
</ParamField>

<ParamField body="lifecycle_hooks" type="list of strings" default={`[]`}>
  List of lifecycle hook `package.json` scripts to run for this package if they exist.
</ParamField>

<ParamField body="npm_auth" type="string" default={`""`}>
  Auth token to authenticate with npm. When using Bearer authentication.
</ParamField>

<ParamField body="npm_auth_basic" type="string" default={`""`}>
  Auth token to authenticate with npm. When using Basic authentication.

  This is typically the base64 encoded string "username:password".
</ParamField>

<ParamField body="npm_auth_password" type="string" default={`""`}>
  Auth password to authenticate with npm. When using Basic authentication.
</ParamField>

<ParamField body="npm_auth_username" type="string" default={`""`}>
  Auth username to authenticate with npm. When using Basic authentication.
</ParamField>

<ParamField body="patch_tool" type="label" default={`None`}>
  The patch tool to use. If not specified, the `patch` from `PATH` is used.
</ParamField>

<ParamField body="patch_args" type="list of strings" default={`["-p0"]`}>
  Arguments to pass to the patch tool.

  `-p1` will usually be needed for patches generated by git.
</ParamField>

<ParamField body="patches" type="list of labels" default={`[]`}>
  Patch files to apply onto the downloaded npm package.
</ParamField>

<ParamField body="url" type="string" default={`""`}>
  Optional url for this package. If unset, a default npm registry url is generated from
  the package name and version.

  May start with `git+ssh://` or `git+https://` to indicate a git repository. For example,

  ```
  git+ssh://git@github.com/org/repo.git
  ```

  If url is configured as a git repository, the commit attribute must be set to the
  desired commit.
</ParamField>

<ParamField body="bins" type="dictionary: String → String" default={`{}`}>
  Dictionary of `node_modules/.bin` binary files to create mapped to their node entry points.

  This is typically derived from the "bin" attribute in the package.json
  file of the npm package being linked.

  For example:

  ```
  bins = {
      "foo": "./foo.js",
      "bar": "./bar.js",
  }
  ```

  In the future, this field may be automatically populated by npm\_translate\_lock
  from information in the pnpm lock file. That feature is currently blocked on
  [https://github.com/pnpm/pnpm/issues/5131](https://github.com/pnpm/pnpm/issues/5131).
</ParamField>

<ParamField body="deps" type="dictionary: String → String" default={`{}`}>
  A dict other npm packages this one depends on where the key is the package name and value is the version
</ParamField>

<ParamField body="lifecycle_build_target" type="boolean" default={`False`} />

<ParamField body="lifecycle_hooks_env" type="list of strings" default={`[]`}>
  Environment variables set for the lifecycle hooks action for this npm
  package if there is one.

  Environment variables are defined by providing an array of "key=value" entries.

  For example:

  ```
  lifecycle_hooks_env: ["PREBULT_BINARY=https://downloadurl"],
  ```
</ParamField>

<ParamField body="lifecycle_hooks_execution_requirements" type="list of strings" default={`["no-sandbox"]`}>
  Execution requirements when running the lifecycle hooks.

  For example:

  ```
  lifecycle_hooks_execution_requirements: ["no-sandbox", "requires-network"]
  ```

  This defaults to \["no-sandbox"] to limit the overhead of sandbox creation and copying the output
  TreeArtifact out of the sandbox.
</ParamField>

<ParamField body="lifecycle_hooks_use_default_shell_env" type="boolean" default={`False`}>
  If True, the `use_default_shell_env` attribute of lifecycle hook actions is set to True.

  See [use\_default\_shell\_env](https://bazel.build/rules/lib/builtins/actions#run.use_default_shell_env)

  This defaults to False to reduce the negative effects of `use_default_shell_env`.
</ParamField>

<ParamField body="package_visibility" type="list of strings" default={`["//visibility:public"]`}>
  Visibility of generated node\_module link targets.
</ParamField>

<ParamField body="replace_package" type="string" default={`""`}>
  Use the specified npm\_package target when linking instead of the fetched sources for this npm package.

  The injected npm\_package target may optionally contribute transitive npm package dependencies on top
  of the transitive dependencies specified in the pnpm lock file for the same package, however, these
  transitive dependencies must not collide with pnpm lock specified transitive dependencies.

  Any patches specified for this package will be not applied to the injected npm\_package target. They
  will be applied, however, to the fetches sources so they can still be useful for patching the fetched
  `package.json` file, which is used to determine the generated bin entries for the package.

  NB: lifecycle hooks and custom\_postinstall scripts, if implicitly or explicitly enabled, will be run on
  the injected npm\_package. These may be disabled explicitly using the `lifecycle_hooks` attribute.
</ParamField>

<ParamField body="name" type="name" default={`""`} />

### Tag: `npm_exclude_package_contents`

Configuration for excluding package contents from npm packages.

This tag can be used multiple times to specify different exclusion patterns for different package specifiers.
More specific package matches override less specific ones (the wildcard "\*" is only used if no specific
package match is found).

By default, `presets` is set to `["basic"]` which excludes common files such as `*.md` and development-related
files. Multiple presets can be combined.

Example:

```
npm.npm_exclude_package_contents(
    package = "*",
    patterns = ["**/docs/**"],
)
npm.npm_exclude_package_contents(
    package = "my-package@1.2.3",
    # Overrides the "*" config for this specific package
    presets = ["yarn_autoclean"],
)
```

<ParamField body="package" type="string" required>
  Package name to apply exclusions to. Supports wildcards like '\*' for all packages.
</ParamField>

<ParamField body="patterns" type="list of strings" default={`[]`}>
  List of glob patterns to exclude from the specified package.
</ParamField>

<ParamField body="presets" type="list of strings" default={`["basic"]`}>
  Which preset exclusion patterns to include. Multiple presets can be combined. Valid values:

  * "basic": basic exclusions such as README files, tests, and development files.
  * "yarn\_autoclean": Yarn autoclean exclusions (see [https://github.com/yarnpkg/yarn/blob/7cafa512a777048ce0b666080a24e80aae3d66a9/src/cli/commands/autoclean.js#L16](https://github.com/yarnpkg/yarn/blob/7cafa512a777048ce0b666080a24e80aae3d66a9/src/cli/commands/autoclean.js#L16))
</ParamField>

### Tag: `npm_replace_package`

Replace a package with a custom target.

This allows replacing packages declared in package.json with custom implementations.
Multiple npm\_replace\_package tags can be used to replace different packages.

Targets must produce `JsInfo` or `NpmPackageInfo` providers such as `js_library` or `npm_package` targets.

The injected package targets may optionally contribute transitive npm package dependencies on top
of the transitive dependencies specified in the pnpm lock file for their respective packages, however, these
transitive dependencies must not collide with pnpm lock specified transitive dependencies.

Any patches specified for the packages will be not applied to the injected package targets. They
will be applied, however, to the fetched sources for their respective packages so they can still be useful
for patching the fetched `package.json` files, which are used to determine the generated bin entries for packages.

NB: lifecycle hooks and custom\_postinstall scripts, if implicitly or explicitly enabled, will be run on
the injected package targets. These may be disabled explicitly using the `lifecycle_hooks` attribute.

Example:

```python theme={null}
npm.npm_replace_package(
    package = "chalk@5.3.0",
    replacement = "@chalk_501//:pkg",
)
```

<ParamField body="package" type="string" required>
  The package name and version to replace (e.g., 'chalk\@5.3.0')
</ParamField>

<ParamField body="replacement" type="label" required>
  The target to use as replacement for this package
</ParamField>

## Module extension: `pnpm`

### Tag: `pnpm`

<ParamField body="name" type="name" default={`pnpm`}>
  Name of the generated repository, allowing more than one pnpm version to be registered.
  Overriding the default is only permitted in the root module.
</ParamField>

<ParamField body="include_npm" type="boolean" default={`False`}>
  If true, include the npm package along with the pnpm binary.
</ParamField>

<ParamField body="pnpm_version" type="string" default={`10.32.1`}>
  pnpm version to use. The string `latest` will be resolved to LATEST\_PNPM\_VERSION.
</ParamField>

<ParamField body="pnpm_version_from" type="label" default={`None`}>
  Label to a package.json file to read the pnpm version from.

  It should appear as an attribute like `"packageManager": "pnpm@10.20.0"`
</ParamField>

<ParamField body="pnpm_version_integrity" type="string" default={`""`} />
