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
| Type | Use for | Notes |
|---|---|---|
node | Node/JS apps (Next.js, Vite, plain node) | default <pm> build + <pm> start (yarn or pnpm, autodetected); docker selects the runtime image |
rails | Ruby on Rails apps | Cloud Native Buildpacks when there is no Dockerfile; Postgres test DB |
meteor | Meteor apps | starts node main.js |
custom | anything else | you provide the jobImage and docker config (both required) |
node-static, storybook | deprecated | use 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/nullskips 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 wherepackage.jsonpostinstall won't run).lint/test/audit— customize ({ command, jobImage, … }) or set tofalseto disable that job.artifactsPaths/artifactsExcludePaths— extra build artifacts (distand.nextare always included).cache— build caching (see thecatladder-pipelinesskill for the caching model).jobImage,jobTags,jobVars,runnerVariables— the CI image, runner tags, build-only env vars, and extra runner variables. AjobImageis 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 aDockerfile).
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.
Related skills
catladder-config— catladder.ts structure and regenerationcatladder-deploys— the matchingdeployconfigcatladder-pipelines— how build jobs, caching and job images workcatladder-secrets— env vars available at build timecatladder-migrate-package-manager— migrating a project from yarn to pnpm (or back)