Skip to main content
deno.com
On this page

Deno and Docker

Using Deno with Docker Jump to heading

Deno provides official Docker files and images.

To use the official image, create a Dockerfile in your project directory:

FROM denoland/deno:latest

# Create working directory
WORKDIR /app

# Copy source
COPY . .

# Compile the main app
RUN deno cache main.ts

# Run the app
CMD ["deno", "run", "--allow-net", "main.ts"]

Best Practices Jump to heading

Use Multi-stage Builds Jump to heading

For smaller production images:

# Build stage
FROM denoland/deno:latest AS builder
WORKDIR /app
COPY . .
RUN deno cache main.ts

# Production stage
FROM denoland/deno:latest
WORKDIR /app
COPY --from=builder /app .
CMD ["deno", "run", "--allow-net", "main.ts"]

Permission Flags Jump to heading

Specify required permissions explicitly:

CMD ["deno", "run", "--allow-net=api.example.com", "--allow-read=/data", "main.ts"]

Development Container Jump to heading

For development with hot-reload:

FROM denoland/deno:latest

WORKDIR /app
COPY . .

CMD ["deno", "run", "--watch", "--allow-net", "main.ts"]

Common Issues and Solutions Jump to heading

  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 Jump to heading

.git
.gitignore
Dockerfile
README.md
*.log
_build/
node_modules/

Available Docker Tags Jump to heading

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 Jump to heading

Common environment variables for Deno in Docker:

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 Jump to heading

FROM denoland/deno:latest

WORKDIR /app
COPY . .

# Run tests
CMD ["deno", "test", "--allow-none"]

Using Docker Compose Jump to heading

// 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 Jump to heading

HEALTHCHECK --interval=30s --timeout=3s \
  CMD deno eval "try { await fetch('http://localhost:8000/health'); } catch { Deno.exit(1); }"

Common Development Workflow Jump to heading

For local development:

  1. Build the image: docker build -t my-deno-app .
  2. Run with volume mount:
docker run -it --rm \
  -v ${PWD}:/app \
  -p 8000:8000 \
  my-deno-app

Security Considerations Jump to heading

  • Run as non-root user:
# 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:
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 Jump to heading

When working with Deno workspaces (monorepos) in Docker, there are two main approaches:

1. Full Workspace Containerization Jump to heading

Include the entire workspace when you need all dependencies:

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 Jump to heading

For smaller images, include only required workspace members:

  1. Create a build context structure:
project-root/
├── docker/
│   └── project-a/
│       ├── Dockerfile
│       ├── .dockerignore
│       └── build-context.sh
├── deno.json
├── project-a/
└── project-b/
  1. Create a .dockerignore:
// filepath: docker/project-a/.dockerignore
*
!deno.json
!project-a/**
!project-b/**  # Only if needed
  1. Create a build context script:
// 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
  1. Create a minimal 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"]
  1. Build the container:
cd docker/project-a
./build-context.sh
docker build -t project-a -f Dockerfile tmp-build-context
rm -rf tmp-build-context

Best Practices Jump to heading

  • 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

Did you find what you needed?

Privacy policy