# Private Packages

> Install private npm packages and Go modules in your builds

If your app depends on private packages, such as an npm scope on GitHub Packages or Go modules in a private GitHub organization, the Encore Cloud build needs a token to fetch them. You add that token in the Cloud Dashboard as a **private package credential**, and every build of the app uses it from then on.

The token is encrypted and never enters the build: the build host fetches private packages on your build's behalf and authenticates to the registry itself. Your code, build hooks, tests and config files never see the token, so you don't need an `NPM_TOKEN` secret or a token in your repository.

## Adding a credential

Open your app in the [Cloud Dashboard](https://app.encore.dev) and go to **Settings > Builds**. In the **Private packages** section, click **Add credential** and choose what it is for:

* **npm package scope** for private npm packages
* **Go modules** for private Go modules

Credentials apply right away, to every build of the app, including production. There is one credential per npm scope or Go module pattern.

### npm package scopes

| Field | Description |
| --- | --- |
| **Scope** | The npm scope, like `@acme`. Every package in the scope is installed from the registry below. |
| **Registry URL** | The `https://` URL the scope is served from, like `https://npm.pkg.github.com` for GitHub Packages. |
| **Username** | Optional. Set it if the registry needs a username and password rather than a token. |
| **Token** | The registry token. For GitHub Packages, use a classic personal access token with the `read:packages` scope. |

The credential takes precedence over your project's own configuration for that scope. If your repository already has an `.npmrc` (or `.yarnrc.yml`) that points the scope at the registry with a `${NPM_TOKEN}` placeholder, you can leave it as it is: the build routes the scope through the build host regardless, and committed lockfiles that record the registry's tarball URLs keep working with `npm ci` and frozen lockfiles. Other settings in your configuration are left alone.

This works with npm, pnpm, Yarn (Classic and Berry) and Bun.

> **Note**
>
> With pnpm 11.0–11.9, `registries` set in `pnpm-workspace.yaml` take precedence over the credential. The same goes for Bun's `[install.scopes]` in `bunfig.toml`. Configure the scope in `.npmrc` instead, or leave it out and let the credential provide it.

### Go modules

| Field | Description |
| --- | --- |
| **Module path pattern** | A [`GOPRIVATE`](https://go.dev/ref/mod#private-modules)-style pattern that starts with the host name, like `github.com/acme/*` or `github.com/acme/internal-lib`. |
| **Username** | Optional. Set it if the host needs a specific login with the token. |
| **Token** | A token with read access to the repositories. For GitHub, a fine-grained or classic personal access token that can read the repositories' contents. |

Modules matching the pattern are fetched directly from their repository host with the token, and are not checked against the public checksum database. Everything else is fetched through the public Go module proxy as usual. You don't need to set `GOPRIVATE` or configure git credentials in your build.

You can add several credentials for the same host, for example one token for `github.com/acme/*` and another for `github.com/partner/*`, which is what GitHub's fine-grained tokens require when your modules span organizations. The most specific pattern wins. Credentials are told apart by the part of the pattern before the first wildcard, so two patterns that share it, like `github.com/acme/foo-*` and `github.com/acme/bar-*` (both `github.com/acme`), can't both be added. To keep separate tokens for different repositories in one organization, name the repositories instead, like `github.com/acme/foo-api` and `github.com/acme/bar-lib`.

## Updating and removing credentials

To rotate a token, click **Edit** next to the credential and enter the new token. Tokens are write-only: the dashboard shows what each credential is for and when it was last changed, but never the token itself. Leave the token field empty to keep the current one when changing other fields. The scope or pattern of a credential can't be changed; remove it and add a new one instead.

Click **Remove** to delete a credential; it takes effect from the next build. Builds that need the private packages fail until you add a new one.

## Permissions

Because a credential reaches every build of the app, including production, only app owners can add, change or remove credentials. Everyone with access to the app can see which credentials exist, but never their tokens. With [custom roles](/docs/platform/management/permissions#custom-roles--permissions) you can grant these permissions separately: *List private package credentials* and *Add, change and remove private package credentials*.
