Docker and containers
Build production containers with official Deno images, a non-root user, cache layers, and least privilege
Multi-stage example
FROM denoland/deno:alpine AS build
WORKDIR /app
# Copy the manifest and lockfile and install dependencies first, so source changes don't invalidate the dependency layer
COPY deno.json deno.lock ./
RUN deno ci
COPY . .
RUN deno install --entrypoint main.ts
FROM denoland/deno:distroless
WORKDIR /app
COPY --from=build /app /app
# The dependency cache lives in DENO_DIR (/deno-dir), not /app — copy it explicitly
COPY --from=build /deno-dir /deno-dir
USER deno
EXPOSE 8000
CMD ["run", "--cached-only", "--allow-net", "--allow-env=PORT", "main.ts"]
Choose debian, alpine, or distroless based on dependencies. If you need a shell, CAs, fonts, or system libraries, do not choose a less observable variant solely for image size.
Production checks
- Pin a Deno image tag or digest; do not release from floating
latest. - Exclude
.git, secrets, coverage, and local caches with.dockerignore. - Run as non-root with a read-only root filesystem; mount only required write paths.
- Make
0.0.0.0andPORTbehavior explicit in the application. - Let the platform send SIGTERM and measure graceful shutdown.
- If runtime dependency resolution has no network, cache during build and verify with
--cached-only.
Official reference: Deno and Docker.