> ## Documentation Index
> Fetch the complete documentation index at: https://nextjs-egg.nyxel.my.id/llms.txt
> Use this file to discover all available pages before exploring further.

# Package Managers

> Configure npm, pnpm, or yarn for dependency installation.

The egg supports three package managers — **npm**, **pnpm**, and **yarn** — and can detect the right one automatically from your lockfile. You control this behavior with the [`PACKAGE_MANAGER`](/configuration/variables#package_manager) variable.

## Auto-Detection

When `PACKAGE_MANAGER` is set to `auto` (the default), the egg inspects your project's lockfile at startup to decide which manager to use:

| Lockfile present | Manager selected |
| ---------------- | ---------------- |
| `pnpm-lock.yaml` | pnpm             |
| `yarn.lock`      | yarn             |
| Neither          | npm              |

<Note>
  pnpm takes priority over yarn in the detection order. If your repository contains both `pnpm-lock.yaml` and `yarn.lock` for any reason, the egg will select pnpm.
</Note>

## Overriding the Package Manager

Set `PACKAGE_MANAGER` to `npm`, `pnpm`, or `yarn` to force a specific manager regardless of which lockfiles are present. This is useful when:

* Your lockfile is absent from the repository (e.g. it is in `.gitignore`)
* You want to enforce a consistent manager across environments
* Auto-detection is picking the wrong manager

You can change this variable from the **Startup** tab of your server in the panel. Restart the server after saving for the change to take effect.

## Install Behavior by Manager

<Tabs>
  <Tab title="npm">
    The egg checks whether `package-lock.json` exists in your project root:

    * **Lockfile present** — runs `npm ci`, which installs exactly the versions recorded in `package-lock.json`. This is deterministic and will fail if the lockfile is out of sync with `package.json`.
    * **No lockfile** — runs `npm install`, which resolves dependencies from `package.json` and generates a fresh lockfile.

    <Warning>
      `npm ci` will fail if your `package-lock.json` is out of sync with `package.json`. This typically happens after manually editing `package.json` without running `npm install` locally. Commit an up-to-date lockfile to your repository to avoid this, or delete `package-lock.json` so the egg falls back to `npm install`.
    </Warning>
  </Tab>

  <Tab title="pnpm">
    pnpm is installed automatically via `npm install -g pnpm` if it is not already present in the container.

    The egg first attempts `pnpm install --frozen-lockfile`, which installs exactly what is recorded in `pnpm-lock.yaml` and refuses to update it. If that fails (for example, because no lockfile is present), it falls back to `pnpm install`.
  </Tab>

  <Tab title="yarn">
    yarn is installed automatically via `npm install -g yarn` if it is not already present in the container.

    The egg first attempts `yarn install --frozen-lockfile`, which installs from `yarn.lock` without modifying it. If that fails (for example, because no lockfile is present), it falls back to `yarn install`.
  </Tab>
</Tabs>

## Deterministic Installs

<Tip>
  Commit your lockfile (`package-lock.json`, `pnpm-lock.yaml`, or `yarn.lock`) to your repository. This ensures the egg installs the exact same dependency versions on every startup — across your local machine, CI, and the panel server — eliminating "works on my machine" issues.
</Tip>

All three managers use a frozen or clean install mode when a lockfile is present, which means:

* Dependencies never silently upgrade between server restarts.
* If a dependency is added to `package.json` but the lockfile is not updated, the install will fail loudly rather than silently installing an unexpected version.

To update your dependencies intentionally, update the lockfile locally and push the change to your repository. The egg will pick up the updated lockfile on the next startup (with `AUTO_UPDATE=1`) or on the next manual restart after you push.
