# Deno Dockerfile Generator

URL: /dockerizer/deno

Generate a production Dockerfile for a Deno app with a pre-cached module graph and an explicit permission set.

## Default configuration

- `appName` (App name): deno-app — Used for the image tag, the compose service and the OCI labels.

- `port` (Port): 8000 — The port the app listens on inside the container. Keep it above 1024 so the process can bind it without root.

- `entrypoint` (Entry file): main.ts — The module Deno runs on start.

- `permissions` (Permissions): --allow-net --allow-env — Deno denies everything by default. List only what the app actually needs — this is the security model, not boilerplate.

- `denoVersion` (Deno version): latest

- `baseVariant` (Base image): alpine — Deno bundles its own runtime, so the base image only supplies libc and the CA certificates.

- `database` (Database service): none — Adds the database to docker-compose.yml with a healthcheck, a named volume and a DATABASE_URL wired into the app.

- `redis` (Redis service): false — Adds Redis to docker-compose.yml and exposes REDIS_URL to the app.

- `cacheMounts` (BuildKit cache mounts): true — Persists the package manager store between builds. Repeat builds skip the download entirely.

- `multiArch` (Multi-architecture build): false — Adds BUILDPLATFORM/TARGETARCH so `docker buildx build --platform linux/amd64,linux/arm64` cross-compiles natively.

- `healthcheck` (Healthcheck): true — Adds a HEALTHCHECK so orchestrators can restart an unresponsive container.

- `tini` (tini init): false — Runs the app under tini so signals and zombie processes are handled properly.

- `ociLabels` (OCI labels): false — Adds org.opencontainers.image.* metadata to the final image.

- `buildSecret` (Build secret mount): false — Reads a private registry token via --mount=type=secret so it never lands in an image layer.

## Generated files

### Dockerfile

Multi-stage build: dependencies, compilation and the runtime image are separate, so only what the app needs at runtime ships.

```docker
# syntax=docker/dockerfile:1
# Generated by Easypanel Dockerizer — https://easypanel.io/dockerizer

# --- Base ---------------------------------------------
FROM denoland/deno:alpine AS base
WORKDIR /app

# --- Dependencies -------------------------------------
FROM base AS deps

# Cache the module graph from the manifests alone so source edits do not re-download it
COPY deno.json* deno.lock* import_map.json* ./
RUN --mount=type=cache,id=deno-cache,target=/deno-dir,sharing=locked \
    deno install --frozen || true

# --- Build --------------------------------------------
FROM base AS build
COPY --from=deps /deno-dir /deno-dir
COPY . .

# Type-check and compile the whole graph ahead of time
RUN --mount=type=cache,id=deno-cache,target=/deno-dir,sharing=locked \
    deno cache main.ts

# --- Runtime ------------------------------------------
FROM denoland/deno:alpine AS runtime
WORKDIR /app
ENV DENO_DIR=/deno-dir
ENV PORT=8000
COPY --from=build --chown=deno:deno /deno-dir /deno-dir
COPY --from=build --chown=deno:deno /app .
USER deno
EXPOSE 8000
STOPSIGNAL SIGTERM

# Lets Docker, Compose and Easypanel see when the app is wedged
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD ["deno", "eval", "--allow-net", "const r = await fetch('http://127.0.0.1:8000/'); Deno.exit(r.ok ? 0 : 1)"]
CMD ["run", "--allow-net", "--allow-env", "main.ts"]

```

### .dockerignore

Keeps the build context small and stops secrets and local dependencies from reaching an image layer.

```bash
# Version control
.git
.gitignore
.github

# Secrets — never bake these into an image layer
.env
.env.*
!.env.example
*.pem
*.key

# Editor and OS noise
.vscode
.idea
.DS_Store
Thumbs.db

# Docs and local tooling
README.md
LICENSE
docs
.editorconfig
docker-compose*.yml
Dockerfile*
.dockerignore

# Deno caches modules inside the image
node_modules
**/node_modules
coverage
.deno

```

### docker-compose.yml

Runs the image locally with its backing services, wired together and health-gated.

```yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - "8000:8000"

```

## Frequently asked questions

### Why does the entrypoint use CMD without `deno`?

The official Deno images set `ENTRYPOINT ["deno"]`, so the command only supplies the subcommand and its flags.

### What if my app needs to write to disk?

Add `--allow-write=/path` to the permissions field, scoped to the directory it actually writes to. Blanket `--allow-write` gives away more than you need.

## Related generators

- [Bun](/dockerizer/bun)

- [Node.js](/dockerizer/nodejs)

- [Hono](/dockerizer/hono)

- [Fastify](/dockerizer/fastify)