GitHub Action
A drop-in replacement for the official setup-node action. Swap one line in your workflow and Nub installs itself, provisions the project's pinned Node, and fronts it on PATH.
A drop-in for actions/setup-node — swap one line:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: nubjs/setup-nub@v0
- run: nub install
- run: nub run testLater steps run the project's pinned Node, the same contract as setup-node. Bare node, npm, and npx resolve to it, because the action puts that Node's bin directory on the runner's PATH.
Read the full docs on github.com. This action accepts the same inputs.
Node version
The action reads the project's pin, in this order:
package.json#/devEngines/runtime.node-version.nvmrc.tool-versions(nodejsornodeline)package.json#/engines/node
It provisions that Node during the setup step, before any of your steps run. With no pin, the setup step provisions nothing and Nub provisions Node when it first runs. The pin lives in the repository, so actions/checkout must run before this action.
Beside setup-node
The action also runs after actions/setup-node in a workflow that keeps it. Only the install line changes:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- uses: nubjs/setup-nub@v0
with:
provision-node: false
- run: npm ci
- run: nub install --frozen-lockfile
- run: npm testNub reads the existing package-lock.json unchanged, and npm test runs the real npm as before. With provision-node: false, the Node that setup-node put on PATH stays in place. The cache: npm line can stay; Nub does not read npm's cache, and this action caches Nub's store by default.
Companion actions
The Nub repository ships three narrower actions for workflows that keep setup-node.
nubjs/nub/setup-node
This action takes the inputs and outputs of actions/setup-node and installs nub beside it:
- uses: actions/checkout@v4
- uses: nubjs/nub/setup-node@v0
- run: npm ci
- run: npm testTwo defaults differ from nubjs/setup-nub:
- Node. With no
node-versioninput, the runner's Node stays when the project's pin allows it or when there is no pin. A pin that excludes the runner's Node is downloaded and put first onPATH, with a notice in the job log. - Package-manager shims. These are on by default, so
npm,pnpm, andyarnin later steps run the version the project pins inpackageManagerordevEngines, provisioned on demand.
Set provision-node: false or shim: false to turn either off. The inputs are listed in its README.
nubjs/nub/install
This action replaces the line that runs npm ci, pnpm install --frozen-lockfile, yarn install --immutable, or bun install --frozen-lockfile, and changes nothing else:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- uses: nubjs/nub/install@v0
- run: npm testNub reads the lockfile unchanged, installs it with its own layout and build-script posture, and caches its store across runs, keyed on the lockfile. Node and the package managers on PATH are left alone.
- uses: nubjs/nub/install@v0
with:
working-directory: apps/web # install a subdirectory
frozen-lockfile: false # let the install update the lockfile
shim: true # package-manager shims for later stepsThe inputs are listed in its README.
nubjs/nub/npm-ci
This action is the npm ci step for a project with a package-lock.json, under npm ci's own contract:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- uses: nubjs/nub/npm-ci@v0
with:
lockfile: package-lock.json
- run: npm test- Every package installs at the version and from the
resolvedURL the lockfile records, checked against itsintegrityhash. Nothing is resolved against the registry. - The action removes
node_modulesfirst and hoists the tree as npm lays it out. - Every lifecycle script runs as it does under npm, under the job's
node. A.nvmrcorenginespin is not consulted, and no Node is downloaded. - The install fails when the lockfile and
package.jsondisagree. - The action hashes the lockfile before and after the install and fails if a byte changed. The hash is its
lockfile-sha256output. - The
argsinput takesnpm ci's own flags, such as--omit=devor--ignore-scripts. A flag the engine does not honor fails the action rather than running npm.
The inputs are listed in its README.
Inputs
| Input | Default | Description |
|---|---|---|
nub-version | latest | Version of Nub to install — any semver range npm understands. |
node-version | Provision this version and front it on PATH instead of the project pin. | |
node-version-file | Read a version from a file and front it on PATH instead of the project pin. | |
cache | auto | Cache Nub's store and provisioned Node toolchains. Auto-enables on a lockfile or packageManager/devEngines; an explicit value wins. |
package-manager-cache | true | Set false to turn off the automatic caching above. |
cache-dependency-path | Lockfile path(s) whose hash keys the cache. | |
cache-key-prefix | Prefix injected into the cache key to scope or bust caches independently. | |
working-directory | checkout root | Directory to resolve the pin and lockfile from, for monorepo subdirectories. |
registry-url | Registry to set up for auth; writes a temporary user-level .npmrc via NPM_CONFIG_USERCONFIG. | |
scope | Scope for a scoped registry; falls back to the repository owner for GitHub Packages. | |
always-auth | false | Write always-auth=true into the .npmrc, to authenticate on every registry request. |
token | github.token | Token for GitHub-API rate-limit relief when resolving Nub's version range, and for Node downloads on GHES. |
shim | false | Run nub pm shim and put the shims first on PATH, so npm, pnpm, and yarn in later steps run the package manager the project pins. |
provision-node | true | Set false to leave Node alone: nothing provisioned, nothing fronted on PATH, and the node-version output empty. |
nub-version
- uses: nubjs/setup-nub@v0
with:
nub-version: ^0.1.0node-version
The action provisions this version and puts it on PATH, so bare node in later steps is this version. Nub itself still runs the project's pin when invoked as nub, and the action warns when the two differ.
- uses: nubjs/setup-nub@v0
with:
node-version: 27.0.0-alpha.0.1.0node-version-file
Accepts .node-version, .nvmrc, and package.json, where it reads devEngines.runtime and then engines.node:
- uses: nubjs/setup-nub@v0
with:
node-version-file: .node-versioncache
Caching is on when the project has a lockfile or a package.json that declares packageManager or devEngines, as with setup-node. The cache key comes from the Node pin and the lockfile, detected in this order:
pnpm-lock.yamlpackage-lock.jsonbun.lockbun.lockbyarn.lock
- uses: nubjs/setup-nub@v0
with:
cache: true # force on; false forces offcache-dependency-path
Override the detected lockfile with a path, a glob, or a newline-separated list. A restore-keys ladder gives a partial warm hit when the lockfile changes.
- uses: nubjs/setup-nub@v0
with:
cache-dependency-path: |
app/pnpm-lock.yaml
packages/*/pnpm-lock.yamlcache-key-prefix
The prefix lands in the cache key as nub-<os>-<arch>-<prefix>-<hash>:
- uses: nubjs/setup-nub@v0
with:
cache-key-prefix: v2working-directory
Use it in a monorepo where package.json and .node-version live below the checkout root:
- uses: nubjs/setup-nub@v0
with:
working-directory: apps/webregistry-url
The action writes a temporary user-level .npmrc through NPM_CONFIG_USERCONFIG and reads the auth token from NODE_AUTH_TOKEN:
- uses: nubjs/setup-nub@v0
with:
registry-url: https://registry.npmjs.org
- run: nub install
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}For GitHub Packages, the scope defaults to the repository owner:
- uses: nubjs/setup-nub@v0
with:
registry-url: https://npm.pkg.github.com
- run: nub install
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}Read the full docs on docs.github.com.
provision-node
Use it in a job where actions/setup-node already put the wanted Node on PATH. Nub still resolves the project's pin when it runs.
- uses: actions/setup-node@v4
with:
node-version: 27.0.0-alpha.0.1.0
- uses: nubjs/setup-nub@v0
with:
provision-node: falseshim
In a project that pins a package manager through packageManager or devEngines.packageManager, npm, pnpm, and yarn in later steps run that pinned version, provisioned on demand. In an unpinned project they fall through to the runner's own tool. The shims do not route those commands into Nub's installer; use nub install for that.
- uses: nubjs/setup-nub@v0
with:
shim: true
- run: pnpm install --frozen-lockfile # the version packageManager pinsOutputs
| Output | Description |
|---|---|
nub-version | The installed Nub version. |
node-version | The Node version provisioned during setup; empty when nothing was provisioned. |
cache-hit | Whether an exact store-cache match was restored; empty on a miss, mirroring actions/cache. |
caching-enabled | Whether caching is active for this run, independent of whether a cache was hit. |
Differences from setup-node
- The
cacheinput is a boolean. A package-manager name (npm,pnpm,yarn,bun) is accepted and treated as on, since Nub keeps one store for every package manager. - The registry
.npmrcis written fresh to$RUNNER_TEMPand pointed at throughNPM_CONFIG_USERCONFIG, rather than merged into the user.npmrc. - The
check-latest,architecture,mirror, andmirror-tokeninputs are accepted and ignored. - The
versioninput is a deprecated alias fornub-versionand emits a warning.
How it works
The action installs the nub CLI from the release archive for the runner's platform into the runner tool cache, verified against the release's sha256 sidecar. If the archive install fails, it falls back to npm install -g @nubjs/nub.
Related
- Node manager — how Nub provisions and pins Node versions.
- Package manager — what
nub installreads, including the.npmrcthe action writes.