--- title: Deno and Docker description: "Complete guide to using Deno with Docker containers. Learn about official Deno images, writing Dockerfiles, multi-stage builds, workspace containerization, and Docker best practices for Deno applications." --- ## Using Deno with Docker Deno provides [official Docker files](https://github.com/denoland/deno_docker) and [images](https://hub.docker.com/r/denoland/deno). 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 . . # Install dependencies (use just `deno install` if deno.json has imports) RUN deno install --entrypoint main.ts # Run the app CMD ["deno", "run", "--allow-net", "main.ts"] ``` ### Best Practices #### Use Multi-stage Builds For smaller production images: ```dockerfile # Build stage FROM denoland/deno:latest AS builder WORKDIR /app COPY . . # Install dependencies (use just `deno install` if deno.json has imports) RUN deno install --entrypoint main.ts # Production stage FROM denoland/deno:latest WORKDIR /app COPY --from=builder /app . CMD ["deno", "run", "--allow-net", "main.ts"] ``` #### Permission Flags Specify required permissions explicitly: ```dockerfile CMD ["deno", "run", "--allow-net=api.example.com", "--allow-read=/data", "main.ts"] ``` #### Development Container For development with hot-reload: ```dockerfile FROM denoland/deno:latest WORKDIR /app COPY . . CMD ["deno", "run", "--watch", "--allow-net", "main.ts"] ``` ### Common Issues and Solutions 1. **Permission Denied Errors** - Use `--allow-*` flags appropriately - Consider using `deno.json` permissions 2. **Large Image Sizes** - Use multi-stage builds - Include only necessary files - Add proper `.dockerignore` 3. **Cache Invalidation** - Separate dependency caching - Use proper layer ordering ### Example .dockerignore ```text .git .gitignore Dockerfile README.md *.log _build/ node_modules/ ``` ### Available Docker Tags Deno provides several official tags: - `denoland/deno:latest` - Latest stable release - `denoland/deno:alpine` - Alpine-based smaller image - `denoland/deno:distroless` - Google's distroless-based image - `denoland/deno:ubuntu` - Ubuntu-based image - `denoland/deno:1.x` - Specific version tags ### Environment Variables Common environment variables for Deno in Docker: ```dockerfile ENV DENO_DIR=/deno-dir/ ENV DENO_INSTALL_ROOT=/usr/local ENV PATH=${DENO_INSTALL_ROOT}/bin:${PATH} # Optional environment variables ENV DENO_NO_UPDATE_CHECK=1 ENV DENO_NO_PROMPT=1 ``` ### Running Tests in Docker ```dockerfile FROM denoland/deno:latest WORKDIR /app COPY . . # Run tests CMD ["deno", "test", "--allow-none"] ``` ### Using Docker Compose ```yaml // filepath: docker-compose.yml version: "3.8" services: deno-app: build: . volumes: - .:/app ports: - "8000:8000" environment: - DENO_ENV=development command: ["deno", "run", "--watch", "--allow-net", "main.ts"] ``` ### Health Checks ```dockerfile HEALTHCHECK --interval=30s --timeout=3s \ CMD deno eval "try { await fetch('http://localhost:8000/health'); } catch { Deno.exit(1); }" ``` ### Common Development Workflow For local development: 1. Build the image: `docker build -t my-deno-app .` 2. Run with volume mount: ```bash docker run -it --rm \ -v ${PWD}:/app \ -p 8000:8000 \ my-deno-app ``` ### Security Considerations - Run as non-root user: ```dockerfile # Create deno user RUN addgroup --system deno && \ adduser --system --ingroup deno deno # Switch to deno user USER deno # Continue with rest of Dockerfile ``` - Use minimal permissions: ```dockerfile CMD ["deno", "run", "--allow-net=api.example.com", "--allow-read=/app", "main.ts"] ``` - Consider using `--deny-*` flags for additional security ## Working with Workspaces in Docker When working with Deno workspaces (monorepos) in Docker, there are two main approaches: ### 1. Full Workspace Containerization Include the entire workspace when you need all dependencies: ```dockerfile FROM denoland/deno:latest WORKDIR /app # Copy entire workspace COPY deno.json . COPY project-a/ ./project-a/ COPY project-b/ ./project-b/ WORKDIR /app/project-a CMD ["deno", "run", "-A", "mod.ts"] ``` ### 2. Minimal Workspace Containerization For smaller images, include only required workspace members: 1. Create a build context structure: ```sh project-root/ ├── docker/ │ └── project-a/ │ ├── Dockerfile │ ├── .dockerignore │ └── build-context.sh ├── deno.json ├── project-a/ └── project-b/ ``` 2. Create a `.dockerignore`: ```text // filepath: docker/project-a/.dockerignore * !deno.json !project-a/** !project-b/** # Only if needed ``` 3. Create a build context script: ```bash // filepath: docker/project-a/build-context.sh #!/bin/bash # Create temporary build context BUILD_DIR="./tmp-build-context" mkdir -p $BUILD_DIR # Copy workspace configuration cp ../../deno.json $BUILD_DIR/ # Copy main project cp -r ../../project-a $BUILD_DIR/ # Copy only required dependencies if grep -q "\"@scope/project-b\"" "../../project-a/mod.ts"; then cp -r ../../project-b $BUILD_DIR/ fi ``` 4. Create a minimal Dockerfile: ```dockerfile // filepath: docker/project-a/Dockerfile FROM denoland/deno:latest WORKDIR /app # Copy only necessary files COPY deno.json . COPY project-a/ ./project-a/ # Copy dependencies only if required COPY project-b/ ./project-b/ WORKDIR /app/project-a CMD ["deno", "run", "-A", "mod.ts"] ``` 5. Build the container: ```bash cd docker/project-a ./build-context.sh docker build -t project-a -f Dockerfile tmp-build-context rm -rf tmp-build-context ``` ### Best Practices - Always include the root `deno.json` file - Maintain the same directory structure as development - Document workspace dependencies clearly - Use build scripts to manage context - Include only required workspace members - Update `.dockerignore` when dependencies change