From f9bf1119225bb06dff47ef62366ca2904cbc11cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 21 May 2026 12:46:35 +0200 Subject: [PATCH] docs(docker): use deno ci for reproducible cached installs Rebases on 2.8 and switches the Dockerfile examples from `deno install --entrypoint main.ts` to `deno ci --prod --skip-types`. `deno ci` is the 2.8 install command intended for CI and image builds: it requires a committed lockfile, wipes any stale node_modules, and runs install with `--frozen` semantics. `--prod` drops devDependencies and `--skip-types` drops `@types/*` packages, both shrinking the resulting image without changing runtime behavior. Manifests (`deno.json`, `deno.lock`, `package.json*`) are copied before the full source tree so the install layer caches across source-only edits, in both the basic and multi-stage examples. Ref #2935 --- runtime/reference/docker.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/runtime/reference/docker.md b/runtime/reference/docker.md index 159defdcc..0261c1ccb 100644 --- a/runtime/reference/docker.md +++ b/runtime/reference/docker.md @@ -14,19 +14,24 @@ To use the official image, create a `Dockerfile` in your project directory: ```dockerfile FROM denoland/deno:latest -# Create working directory WORKDIR /app -# Copy source -COPY . . +# Copy manifests first so the dependency install layer caches across +# source-only edits +COPY deno.json deno.lock package.json* ./ +RUN deno ci --prod --skip-types -# Install dependencies (use just `deno install` if deno.json has imports) -RUN deno install --entrypoint main.ts +# Then copy the rest of the source +COPY . . -# Run the app CMD ["deno", "run", "--allow-net", "main.ts"] ``` +[`deno ci`](/runtime/reference/cli/ci/) performs a reproducible install from +`deno.lock`. `--prod` skips `devDependencies`, and `--skip-types` drops +`@types/*` packages — both shrink the resulting image without affecting +runtime behavior. + ### Best Practices #### Use Multi-stage Builds @@ -39,9 +44,14 @@ FROM denoland/deno:latest AS builder # Point Deno's cache at a known location so it can be copied to the next stage ENV DENO_DIR=/deno-dir WORKDIR /app + +# Copy manifests first so the dependency install layer caches across +# source-only edits +COPY deno.json deno.lock package.json* ./ +RUN deno ci --prod --skip-types + +# Then copy the rest of the source COPY . . -# Install dependencies (use just `deno install` if deno.json has imports) -RUN deno install --entrypoint main.ts # Production stage FROM denoland/deno:latest @@ -53,7 +63,7 @@ COPY --from=builder /deno-dir /deno-dir CMD ["deno", "run", "--allow-net", "main.ts"] ``` -Without copying `$DENO_DIR`, `deno install` only writes to Deno's global cache +Without copying `$DENO_DIR`, `deno ci` only writes to Deno's global cache inside the builder stage — those files do not travel with `COPY --from=builder /app .`, so the container re-downloads dependencies on first run.