Create repository-matched Dockerfiles for Unkey Deploy, which is currently public beta. Inspect the live repo before writing anything; a Dockerfile that builds but starts the wrong app, ignores PORT, writes to read-only filesystem paths, or leaks secrets is a failed result.
Workflow
- Inspect the repository.
- Ask one blocking question at a time if required facts are ambiguous.
- Write the Dockerfile next to the deployed app and
.dockerignoreat the build-context root. - Validate the build shape as far as the local repo allows.
- Report exact Unkey app settings.
Inspect First
Identify these facts from source before editing:
- Runtime and pinned version: Bun, Node.js, Python, Go, Rust, Java, etc.
- Package manager and lockfile:
bun.lock,package-lock.json,pnpm-lock.yaml,yarn.lock,uv.lock,poetry.lock,Cargo.lock,go.sum. - Build tool and output: Next.js, Vite,
tsc, esbuild, Turborepo, Nx,go build,cargo build, etc. - Start command and port handling. Search for
PORT,process.env.PORT,Bun.env.PORT,os.getenv("PORT"), framework configs, and route/server entrypoints. - Monorepo shape: workspace manifests,
turbo.json,nx.json,go.work, Cargo workspace members, packageworkspace:*edges, internal imports. - Existing Dockerfile,
.dockerignore, compose files, Procfiles, deployment docs, or CI deploy steps to preserve intent. - Build-time requirements: codegen, private packages, database clients, migrations, native libraries, or secrets.
- Runtime writes: whether the app writes to disk, and whether it must use
/tmporUNKEY_EPHEMERAL_DISK_PATH.
Use the repo's own files as source of truth. Prefer rg/rg --files for discovery.
If a task depends on exact current Unkey platform behavior, verify the relevant Unkey docs before editing because Deploy is still changing during beta.
Ask On Ambiguity
Do not guess when the answer affects the image that will run in production. Stop and ask one concise question, then continue after the answer.
Ask when any of these are unclear:
- Which app in a monorepo should be deployed.
- Which runtime version to target when the repo does not pin one.
- Which package manager to use when multiple lockfiles are present.
- Which build or start command is correct when several are plausible.
- Which port the app listens on if
PORTsupport is not clear. - Whether the build needs secrets, and which secret-backed commands need them.
- Whether runtime disk writes need
/tmpor configured ephemeral storage.
Unkey Runtime Rules
These are Unkey Deploy requirements, not generic Docker preferences:
- Listen on the
PORTenvironment variable. Default to8080only when setting a fallback in app code or runtime environment. - Use exec-form
CMD, such asCMD ["bun", "run", "start"], so the app process receivesSIGTERM. - Run one foreground process. Avoid
supervisord, background jobs, and wrapper shells that swallow signals. - Treat the root filesystem as read-only at runtime unless Unkey documentation for the target environment says otherwise.
- Treat
/tmpas small memory-backed scratch space. - Use
/dataonly when ephemeral storage is configured; Unkey exposes the mount path inUNKEY_EPHEMERAL_DISK_PATH. - Never put secret values in Docker
ARGorENV.
For build-time secrets, use a mounted secret file:
ARG UNKEY_SECRETS_ID
RUN --mount=type=secret,id=${UNKEY_SECRETS_ID},target=/run/secrets/.env \
set -a && . /run/secrets/.env && set +a && \
<build command>
Declare ARG UNKEY_SECRETS_ID in every stage that mounts the secret; Docker ARG values are not inherited across stages.
Dockerfile Standards
- Use a multi-stage build: dependency/build stage plus a minimal runtime stage.
- Pin the base image to a concrete version such as
oven/bun:1.2.15-alpine,node:22-alpine,python:3.12-slim,golang:1.24-alpine, or a Rust image matchingrust-toolchain.toml. - Optimize dependency caching: copy manifests and lockfiles first, install dependencies, then copy source.
- Prefer Bun when the repo is Bun-native. Respect the repo when it uses pnpm, npm, yarn, uv, Cargo, or Go modules.
- Run as a non-root user in the final image.
- Install only runtime OS packages in the final stage.
- Copy only runtime artifacts into the final stage.
- Configure runtime caches, uploads, SQLite files, logs, and temp files to use
/tmporUNKEY_EPHEMERAL_DISK_PATH, not project directories. - Use framework-specific standalone outputs when available, such as Next.js
output: "standalone". - Keep
CMDin the Dockerfile unless the platform must override it.
Monorepos
If the repo is a monorepo:
- Read workspace configuration before choosing paths.
- Ask which app to deploy if multiple apps fit the request.
- Ship only the target app and its workspace dependencies.
- Prefer the monorepo's pruning/deploy feature when available:
pnpm deploy,turbo prune, Nx production builds, or equivalent. - Place the Dockerfile next to the target app.
- Keep the build context at the repo root when workspace dependencies require it.
- In the final response, state the exact Unkey
Root directoryandDockerfile pathvalues.
.dockerignore
Create .dockerignore at the build-context root. Always exclude:
.git
.gitignore
node_modules
.next
dist
build
out
coverage
.env
.env.*
*.log
.DS_Store
.vscode
.idea
README.md
Dockerfile
.dockerignore
Add repo-specific entries, such as:
- Rust:
target/ - Go:
vendor/unless vendoring is intentionally used - Python:
__pycache__/,.venv/,.pytest_cache/,.ruff_cache/ - Turborepo:
.turbo/ - Vite/SPA: generated output directories
- Tests, fixtures, docs, screenshots, local databases, and caches that are not needed for the build
Do not ignore files required by the build context or workspace dependency resolution.
Validation
Run the highest-signal local checks that are reasonable:
- Parse or inspect the Dockerfile if tooling exists.
- Run the repo's package install/build/test commands when feasible.
- Run
docker buildif Docker is available and the build does not require unavailable secrets. - If Docker cannot run, explain the exact skipped validation.
Do not fake a container smoke test. If the app's port handling is uncertain after source inspection, ask or flag it.
Final Response
Report:
- Dockerfile path.
.dockerignorepath.- Unkey
Root directory. - Unkey
Dockerfile path. - Port only if the app does not use the default
8080fallback or requires special configuration. - Start command only if the platform should override the Dockerfile
CMD; usually leave it empty. - Validation performed and any skipped checks.