Skip to main content

Component builds with catladder

Each component in catladder.ts has a build config that catladder turns into the setup/lint/test/build CI jobs and the deployable Docker image. Change the build in catladder.ts and regenerate (yarn catenv) — never hand-edit generated pipeline files (see the catladder-config skill).

components: {
www: {
dir: "frontend",
build: {
type: "node", // node | rails | meteor | custom (+ deprecated node-static/storybook)
buildCommand: "yarn build",
startCommand: "yarn start",
},
deploy: { /* see catladder-deploys */ },
},
}

Set build: false to disable building for a component (e.g. a deploy-only or docker-tag component).

Node-family builds work with yarn or pnpm: catladder autodetects the package manager (from the packageManager field in package.json or the lockfile) and generates the matching install commands, caches and default build/lint/test commands. Override with packageManager: "pnpm" | "yarn" at the top level of catladder.ts if needed. The meteor build type is yarn-only.

pnpm gotchas: dependency build scripts must be approved in pnpm-workspace.yaml (allowBuilds map since pnpm 11, onlyBuiltDependencies list on pnpm 10); pnpm runs the root prepare script even during the production install in the docker build — guard husky with "prepare": "husky || true"; pnpm run prints a banner to stdout, so use pnpm --silent run in piped commands.

Build types

TypeUse forNotes
nodeNode/JS apps (Next.js, Vite, plain node)default <pm> build + <pm> start (yarn or pnpm, autodetected); docker selects the runtime image
railsRuby on Rails appsCloud Native Buildpacks when there is no Dockerfile; Postgres test DB
meteorMeteor appsstarts node main.js
customanything elseyou provide the jobImage and docker config (both required)
node-static, storybookdeprecateduse type: "node" + docker: { type: "nginx" }

A component can also reuse a shared workspace build instead of a type: build: { from: "web" } (see workspace builds below).

Common options (all standalone build types)

  • buildCommand — the build step (string | string[] | null | false; false/null skips building).
  • startCommand — how the app is started at runtime.
  • postInstall — commands run after the package-manager install (node family; needed e.g. for Yarn PnP where package.json postinstall won't run).
  • lint / test / audit — customize ({ command, jobImage, … }) or set to false to disable that job.
  • artifactsPaths / artifactsExcludePaths — extra build artifacts (dist and .next are always included).
  • cache — build caching (see the catladder-pipelines skill for the caching model).
  • jobImage, jobTags, jobVars, runnerVariables — the CI image, runner tags, build-only env vars, and extra runner variables. A jobImage is a concrete image url or { image: "<name>" } referencing a project image (see below).
  • docker — the image build strategy: a built-in ({ type: "nginx" | "node" | "meteor" }) or { type: "custom" } (expects a Dockerfile).

Project images (custom CI job images)

When a job needs a toolchain catladder doesn't ship (Java, Playwright, …), declare a Docker image at the top level under images and reference it in any jobImage field (build, test.jobImage, custom/pages deploy, verify):

images: {
// (a) a directory in the repo (default context = the dir)
"java-build": {
dir: "docker/java-build", // contains the Dockerfile
buildArgs: { MAVEN_VERSION: "3.9.9" }, // optional, part of the content hash
hashExtraPaths: ["shared/settings.xml"], // optional extra hashed+watched files
},
// (b) inline (default context = repo root); materialized into
// .catladder-generated/images/project/<name>/Dockerfile
"db-tools": {
dockerfile: ["FROM alpine:3.21", "RUN apk add --no-cache postgresql17-client"],
},
},
components: {
api: {
build: { type: "custom", jobImage: { image: "java-build" }, docker: { type: "custom" } },
},
}

dir and dockerfile are mutually exclusive. context overrides the build context (relative to the repo root) — needed when the image COPYs files from outside its dir.

Catladder generates a 🐳 image <name> job (setup stage) that builds the image content-hashed into the project registry (…/job-images/<name>:<hash>) and skips when it already exists — works on GitLab and GitHub.

The build context is not hashed (it can be the whole repo) — only the Dockerfile / dir, buildArgs and hashExtraPaths are. Files pulled in via COPY that should trigger a rebuild belong in hashExtraPaths.

Generation (yarn catenv) fails fast on an undeclared image name, a missing dir, or a dir without a Dockerfile.

Workspace builds (monorepos)

For a shared build across several components, declare it once at the top level under builds and reference it from each component:

builds: {
web: { type: "node", dir: "packages/web", buildCommand: "yarn build" },
},
components: {
www: { dir: "packages/web", build: { from: "web" }, deploy: { /* … */ } },
}

Only type: "node" workspace builds exist today.

Full option reference

See references/build-types.md for every build type's options, the docker sub-config, and the exact defaults.

  • catladder-config — catladder.ts structure and regeneration
  • catladder-deploys — the matching deploy config
  • catladder-pipelines — how build jobs, caching and job images work
  • catladder-secrets — env vars available at build time
  • catladder-migrate-package-manager — migrating a project from yarn to pnpm (or back)