Choose the deployment path your platform exposes:

  1. GitHub Actions — use nubjs/setup-nub@v0 to install Nub, provision the project's Node, and cache the store.
  2. Containers — use ghcr.io/nubjs/nub as the base image. It contains Node and Nub for linux/amd64 and linux/arm64.
  3. Managed builders — install Nub with the installer or add @nubjs/nub as a devDependency when the platform owns the install step.
PlatformDeployment pathWhere Nub runs
VercelInstaller or devDependencyInstall and build; Vercel Functions still use Vercel's Node runtime
CloudflarePreinstalled in Workers Builds; devDependency on PagesBuild only; Workers use Cloudflare's runtime
RailwayDockerfileBuild and runtime
RenderDockerfileBuild and runtime
AWS LambdaDockerfile with Lambda Web AdapterBuild and runtime
Google Cloud RunDockerfileBuild and runtime

Managed builders

A hosted builder that runs the install from your lockfile cannot resolve Nub until the project supplies it:

sh: nub: not found

Add the CLI as a devDependency and call it from a package script:

package.json
{
  "devDependencies": {
    "@nubjs/nub": "^0.7.5"
  },
  "scripts": {
    "build": "nubx vite build"
  }
}

The package exposes both nub and nubx. npm, pnpm, Yarn, Bun, and Nub all link those commands without running a dependency lifecycle script, and the Nub launcher sets its own executable bit at runtime.

Keep development dependencies enabled for the build. Use the installer or a Dockerfile when the platform installs production dependencies only.

Container services

The official image starts from Node, installs Nub, and runs as the non-root node user. A web service only needs a Dockerfile and an application that listens on 0.0.0.0 at the provider's PORT:

Dockerfile
FROM ghcr.io/nubjs/nub:0.7.5

COPY --chown=node:node package.json package-lock.json ./
RUN nub ci

COPY --chown=node:node . .
EXPOSE 8080
CMD ["nub", "run", "start"]

Change package-lock.json to the lockfile the project already uses. Nub reads npm, pnpm, Bun, and Yarn lockfiles.

See Docker for the server contract and image variants.

GitHub Actions and registries

The setup action prepares the runner for tests and build scripts. Standard Docker actions can then build the application image from the Dockerfile above and publish it to GHCR:

.github/workflows/image.yml
name: Image
on:
  push:
    branches: [main]

permissions:
  contents: read
  packages: write

jobs:
  image:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: nubjs/setup-nub@v0
      - run: nub ci
      - run: nub run test
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

Railway and Render can pull an application image from GHCR directly. AWS Lambda requires ECR, while Google recommends Artifact Registry for Cloud Run; the provider pages show those registry-specific steps.

Read the full docs on docs.github.com.

Node versions

A managed builder selects Node, and Nub augments that version. Pin Node with the source the platform supports, normally .node-version, .nvmrc, or package.json#engines.node.

A container carries its own Node version. Pin the Nub image tag and update it deliberately when you want a new Nub or Node release.

Environments driven by .tool-versions can also provision the CLI through mise: mise use nub@latest puts nub and nubx on PATH.