Skip to content
Docs menu / docker

@konfig.ts/docker

@konfig.ts/docker generates Dockerfiles for the apps in a Bun or Node monorepo. You write one docker.ts spec next to each app and the package works out the rest: it resolves the app’s transitive workspace dependencies and emits a Dockerfile that copies exactly those packages, so there is no hand-maintained COPY list to keep in sync. The output is a production multi-stage Dockerfile with base, deps, builder, and runner stages (plus a prod-deps stage when runner.production is set). If the spec has a dev block, it also emits a Dockerfile.dev made of the base and dev stages. The package stops at Dockerfiles: it does not build, push, tag, or sign images.

Install

Terminal window
bun add -d @konfig.ts/docker

The base image tags come from the app’s package.json. It must set engines.<runtime> and engines.<package manager>, for example engines.bun, or engines.node plus engines.pnpm. A missing entry fails with EngineVersionMissing.

Usage

The API spec from the full-stack example. runner.production re-runs a production install after trimming workspaces to the closure.

apps/api/docker.ts
export default Docker.app({
  target: "apps/api",
  runner: {
    production: true,
    workdir: "/app/apps/api",
    copy: [Docker.copy.workspaceSourceAll()],
    expose: 8080,
    cmd: ["bun", "run", "src/main.ts"],
    env: {
      // per-env values and secrets come from Environment.bind, not here
      LOG_LEVEL: "info"
    },
    healthcheck: {
      tag: "HealthcheckHttpGet",
      path: "/healthz",
      port: 8080,
      interval: "15s",
      timeout: "3s",
      retries: 3
    }
  },
  dev: {
    cmd: ["bun", "--watch", "src/main.ts"],
    expose: 8080
  }
})

Render, write, or check the files with the CLI, then build with the monorepo root as the Docker context:

Terminal window
konfig docker preview apps/api # render to stdout
konfig docker write apps/api # writes apps/api/Dockerfile and Dockerfile.dev; refuses to overwrite files without the konfig header unless --force
konfig docker diff apps/api # non-zero exit if the on-disk files drifted
docker build -f apps/api/Dockerfile .

Surface

ExportPurpose
Docker.appThe spec entrypoint; returns a DockerApp
Docker.copybuilderArtifact({ src, dst, chown? }), workspaceSource(name), workspaceSourceAll(), path({ src, dst, from?, chown? })
Docker.runtimebun({ alpine? }), node({ alpine? }); alpine defaults to true
Docker.pmbun(), npm(), pnpm(), yarn({ variant? }); auto-detected from the root lockfile when omitted
Docker.buildscript(name), command(argv), none(); when omitted, script("build") if the app has a build script, else none()
Docker.healthcheck, Docker.user, Docker.platformhttpGet({ path, port, ... }) / command({ argv, ... }); nonRoot({ uid?, gid?, name? }) / root(); linuxAmd64() / linuxArm64() / multi([...])
DockerSpec, RunnerSpec, DevSpec, decodeDockerSpec, decodeDockerSpecSyncSchemas and decoders for the spec; the atom schemas (CopyAtom, RuntimeAtom, PackageManagerAtom, BuildAtom, HealthcheckAtom, UserAtom, PlatformAtom) are exported too
findRoot, allWorkspaces, closureOf, detectPmWorkspace graph services
buildIR, lower, prepareContext, validateSpec, emit, render, renderFile, renderHeader, extractHeader, HEADER_MARKER, sha256HexBuilding the intermediate representation and Dockerfile rendering with a hashed header
bunPm, npmPm, pnpmPm, bunRuntime, nodeRuntimePackage manager and runtime implementations
isDockerApp, makeDockerApp, DockerAppTypeId, PACKAGE_NAMESpec identification helpers

Errors

Every failure the package can produce is a tagged error, and AnyDockerError is the union of all of them.

ErrorWhen it is raised
MonorepoRootNotFoundNo monorepo root could be found walking up from the starting directory
WorkspaceNotFoundThe target app is not a workspace of the monorepo
UnsupportedPmThe package manager could not be determined: no packageManager field and either no recognized lockfile or several conflicting ones
CircularWorkspaceDepThe workspace graph contains a cycle
EngineVersionMissingThe app’s package.json lacks the required engines.* entry
SpecDecodeErrorThe docker.ts spec did not decode against the schema
BuildScriptMissingThe spec names a build script the app’s package.json does not define
WorkspaceSourceUnknownA workspaceSource(name) copy names a workspace outside the app’s closure
SharedRootFileMissingA file listed in sharedRootFiles does not exist at the monorepo root
PlatformMultiUnsupportedDocker.platform.multi([...]) was used; a single FROM --platform line cannot express multiple platforms
DockerWriteRefusedwrite would overwrite a file that lacks the konfig header and --force was not given
DockerWriteErrorWriting a Dockerfile to disk failed

Requirements

  • effect@^4.0.0-rc.111 as a peer dependency (Effect 4, release-candidate line).
  • Depends on @konfig.ts/core and yaml.
  • Runtime: Bun recommended; Node >= 23.6 works; Node 22.6 to 23.5 with --experimental-strip-types; tsx works.

Source and README: packages/docker.