Guides
Build a template from a Dockerfile
Turn a Dockerfile into template build steps with the temper CLI or the TypeScript SDK, and see which instructions map to what.
The template API takes build steps, not Dockerfiles (see Templates). The TypeScript SDK translates a Dockerfile
into those steps, reading COPY sources from your build context, and it ships a temper command that does the translation and the
build in one go. You can use it from any language: the translation is plain JSON.
An example Dockerfile
FROM temper/default
ARG NODE_MAJOR=22
ENV APP_HOME=/srv/app
WORKDIR $APP_HOME
RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg poppler-utils \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - \
&& apt-get install -y nodejs
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --chmod=755 bin/ bin/
COPY src/ src/
ENV PATH=/srv/app/bin:$PATH
CMD ["node", "src/server.js"]FROM temper/default is the platform's runtime (Debian 13 with systemd). To build on another template of yours, write
FROM temper/<name>:<version>, for example FROM temper/base:3.
deb.nodesource.com isn't one of the registries builds can reach by default, so add it to your developer-level
egress allowlist before building this one.
Build it with the CLI
The temper command comes with the TypeScript SDK. It reads TEMPER_API_KEY and TEMPER_BASE_URL like the SDKs do.
npm install --save-dev @temper-hq/sdk
# Print the steps the Dockerfile translates to (warnings go to stderr)
npx temper template translate -f Dockerfile
# Translate, start the build and follow its log until it is ready or failed
npx temper template build web-tools 1 -f Dockerfile --context . --build-arg NODE_MAJOR=22
npx temper template list
npx temper template get web-tools 1
npx temper template delete web-tools 1The Dockerfile defaults to ./Dockerfile and the build context to the Dockerfile's directory. The context's .dockerignore is honoured,
so node_modules and the like stay out of COPY.
Build it from code
In Node, templateFromDockerfile (from @temper-hq/sdk/node) reads the Dockerfile and its context and returns
{ from, steps, start, warnings }, ready for templates.createVersion.
import { Temper } from "@temper-hq/sdk";
import { templateFromDockerfile } from "@temper-hq/sdk/node";
const temper = new Temper();
const t = await templateFromDockerfile("./Dockerfile", { buildArgs: { NODE_MAJOR: "22" } });
for (const w of t.warnings) console.warn(w);
await temper.templates.createVersion("web-tools", "1", { from: t.from, steps: t.steps, start: t.start });
await temper.templates.waitForVersion("web-tools", "1", { onPoll: (v) => console.log(v.state) });Outside Node, translateDockerfile(text, { context }) does the same with any source of files; memoryContext({ "app.py": "..." })
builds a context from strings or bytes.
From Python or Go, translate with the CLI and pass the JSON to the SDK:
import json
import subprocess
from temper_hq import Temper
t = json.loads(subprocess.run(
["npx", "temper", "template", "translate", "-f", "Dockerfile"], check=True, capture_output=True, text=True
).stdout)
with Temper() as temper:
temper.templates.create_version("web-tools", "1", steps=t["steps"], from_=t["from"], start=t["start"])
temper.templates.wait_for_version("web-tools", "1")out, err := exec.Command("npx", "temper", "template", "translate", "-f", "Dockerfile").Output()
if err != nil {
log.Fatal(err)
}
var t struct {
From *string `json:"from"`
Steps []temper.TemplateStep `json:"steps"`
Start *temper.TemplateStart `json:"start"`
}
if err := json.Unmarshal(out, &t); err != nil {
log.Fatal(err)
}
p := temper.CreateTemplateVersionParams{Steps: t.Steps, Start: t.Start}
if t.From != nil {
p.From = *t.From
}
_, err = client.Templates.CreateVersion(ctx, "web-tools", "1", p)How instructions translate
| Instruction | Becomes |
|---|---|
FROM temper/default | No base: the platform's runtime. |
FROM temper/<name>:<version> | from: "<name>:<version>". |
RUN (shell form, exec form, heredocs) | A run step. Values of ARGs in scope are exported at the start of the command. |
COPY, ADD (local files) | One copy step per file. Text stays text; binary files are sent as base64. File permissions are kept; --chmod overrides them. |
COPY --chown=... | The copy steps, then a run step with chown. |
ENV | An env step. $VAR and ${VAR} are expanded, with $PATH standing for the runtime's default PATH. |
ARG | Its value (from --build-arg or the default) is used for expansion and exported in later RUN steps; it isn't kept in the template. |
WORKDIR | A workdir step. Relative paths resolve against the previous one. |
CMD, ENTRYPOINT | start. An exec-form ENTRYPOINT and CMD are combined into one argv, as Docker does. |
EXPOSE, HEALTHCHECK, STOPSIGNAL, VOLUME, LABEL, MAINTAINER | Ignored, with a warning. |
These fail the translation with an error that names the line:
- Any other
FROM. Install what a base image would provide withRUNsteps instead. - Multi-stage builds: a second
FROM, orCOPY --from. Build artifacts beforehand andCOPYthem in, or build them in aRUNstep. USERother than root. Environments have a single user,agent, which runs your agent and thestartcommand; build steps run as root.ADDof a URL or a git repository (useRUN curl ...), andADDof a local archive, which Docker would unpack (useCOPYandRUN tar -x).SHELL(steps always use/bin/sh -c),ONBUILD, andRUN --mount.- More than 4 MiB of files from
COPYandADDtogether. Download large files in aRUNstep.
A $PATH in a Dockerfile that builds on another template expands to the runtime's default PATH, not the base template's; the
translation warns when that happens.