
# GitHub Actions

> Set up Node.js, a package manager, and dependencies in one step.

`setup-jup` can replace `actions/setup-node` and `corepack enable`. It reads your
project pins, installs the matching tools, restores their caches, and installs
dependencies.

```yaml
- uses: actions/checkout@v6
- uses: unjs/setup-jup@85aa1e9e4cd2995fba3bee414cde74bf88637a2c # v1.0.0
- run: pnpm test
```

Your project pins choose the versions. The action reports the versions it used.

The action lives in [unjs/setup-jup](https://github.com/unjs/setup-jup) and is
versioned separately from jup: pinning one does not pin the other. Pin the
action by commit, with the release named beside it as above, and pin jup itself
with the `jup-version` input. Published release tags such as `v1.0.0` are never
moved, so they work as pins too.

The action needs `node` on `PATH` to start. GitHub-hosted runners already have
it. Install Node.js first on other runners. jup then installs the Node.js version
your project needs.

## Examples

Choose a Node.js version and install dependencies in a later step:

```yaml
- uses: unjs/setup-jup@85aa1e9e4cd2995fba3bee414cde74bf88637a2c # v1.0.0
  with:
    node-version: 22
    install: false
- run: pnpm install --frozen-lockfile
```

Or pass install arguments through the action:

```yaml
- uses: unjs/setup-jup@85aa1e9e4cd2995fba3bee414cde74bf88637a2c # v1.0.0
  with:
    install: --frozen-lockfile
```

Test more than one Node.js version:

```yaml
strategy:
  matrix:
    node-version: [22, 24]
steps:
  - uses: actions/checkout@v6
  - uses: unjs/setup-jup@85aa1e9e4cd2995fba3bee414cde74bf88637a2c # v1.0.0
    with:
      node-version: ${{ matrix.node-version }}
  - run: pnpm test
```

Set up one package in a monorepo:

```yaml
- uses: unjs/setup-jup@85aa1e9e4cd2995fba3bee414cde74bf88637a2c # v1.0.0
  with:
    working-directory: packages/app
```

jup searches parent directories, so the package can use a pin from the root.

## Inputs

| Name | Default | Meaning |
| --- | --- | --- |
| `node-version` | `lts` | A Node.js version, range, or tag. Project pins still win. An empty value uses jup's default. `lts/*` becomes `lts`; `node` and `current` become `latest`; a leading `v` is removed. |
| `jup-version` | `latest` | The jup npm version to install. Use an exact version for repeatable jobs. |
| `package-managers` | `auto` | Space-separated tools to shim. `auto` shims the full table, including bun and Deno. `none` shims no package manager. Node.js is always shimmed. |
| `cache` | `true` | Cache jup's store in `JUP_HOME`. |
| `cache-dependencies` | `true` | Cache the package manager's store. |
| `install` | `true` | Install dependencies. `false` skips this. Any other value is passed to the pinned manager. A project with no manager pin is not installed. |
| `working-directory` | `.` | The directory where jup starts project discovery. |

## Outputs

| Name | Meaning |
| --- | --- |
| `node-version` | The exact Node.js version selected by the project and jup. |
| `node-path` | The absolute path to the `node` shim. |
| `package-manager` | The pinned manager name, or an empty value. |
| `bin-directory` | The shim directory added to `PATH`. |
| `jup-home` | The `JUP_HOME` value used by later steps. |

## Job environment

Later steps receive:

- A new first entry in `PATH` with the jup shims.
- `JUP_HOME` and `JUP_SHIM_DIRECTORY`.

Values set by the caller are kept. No other variables are exported. Cache keys
start with `setup-jup-`.

## Differences from `actions/setup-node`

| | `actions/setup-node` | `setup-jup` |
| --- | --- | --- |
| Version source | Action inputs | Action input, project pin, or jup default |
| `lts/*` | Uses an LTS name | Uses jup's `lts` tag |
| Package managers | Needs another setup step | jup verifies and shims the pinned manager |
| Dependencies | Needs another run step | Can run the pinned manager's install command |
| Integrity | Checks downloads | Also checks host signatures ([security](/security)) |
| `npm` | Uses the copy bundled with Node.js | Uses the project pin |
| `node` | Runs an extracted binary | Runs a shim that follows project pins |

The action does not support `registry-url`, `scope`, `always-auth`, `mirror`, or
problem matchers. jup reads `.npmrc` for its own requests. See
[registries](/registry).

## Cache safety

The action caches tools and dependencies separately. It does not cache
`<JUP_HOME>/self` because that file contains a runner-specific Node.js path.

The jup cache key includes the host, requested versions, and project input files.
The dependency cache key includes lockfiles.

::warning
A restored `JUP_HOME` contains executable code. Do not share a release cache with
untrusted fork jobs.
::

## Next steps

For other CI systems, containers, and offline use, see [CI and offline use](/ci).
See [project pins](/projects) and [commands](/commands) for jup behavior.
