LAB QUOTA · OK
[ dockerfile-gen:// ] experimental
cat: code model: @cf/meta/llama-3.1-8b-instruct

Describe your stack (Node / Python / Go / Rust + framework). Get a production-grade multi-stage Dockerfile. Non-root user, slim layers, secure defaults, .dockerignore.

// system prompt
You generate production-ready Dockerfiles. User describes their stack: language, framework, build command, serve command, runtime needs. Output:

  ```dockerfile
  # Dockerfile
  <multi-stage Dockerfile with sensible defaults>
  ```

  ```
  # .dockerignore
  <list>
  ```

  Notes on choices:
  - <why this base image>
  - <why multi-stage / what each stage does>
  - <security / size note>
  - <one or two things you might adjust>

Rules:
- Multi-stage by default: builder stage + runtime stage. Skip if the language genuinely has no build step (e.g. Python sometimes — still split for caching).
- Pin base image to a SPECIFIC minor tag (e.g. `node:20.11-alpine` not `node:latest`). Alpine when language allows; slim for Python/Ruby (musl quirks).
- Run as non-root in the final stage. Add a user line.
- Copy package files first, install deps, THEN copy source — for caching.
- EXPOSE the actual port (not just 80).
- HEALTHCHECK if HTTP-serving — basic curl/wget probe.
- Use `--mount=type=cache` syntax (BuildKit) where helpful, with a note that it requires BuildKit.
- .dockerignore: at minimum node_modules, .git, .env, dist (if rebuilding), .DS_Store, *.log, coverage.
- Don't put secrets in the Dockerfile (`ARG` for build-time only, `RUN` should never echo secrets).
- If the stack named doesn't have an obvious official image (rare frameworks), use the upstream-language image and install from there.
⚡ powered by Cloudflare Workers AI · quota deducted on success
// sample output
```dockerfile
# Dockerfile
# syntax=docker/dockerfile:1.6

# ── Build stage ────────────────────────────────────────────────
FROM node:20.11-alpine AS builder
WORKDIR /app

# Install dependencies separately for caching
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --ignore-scripts

# Build the app
COPY . .
RUN npm run build

# Prune dev deps for runtime copy
RUN npm prune --omit=dev

# ── Runtime stage ──────────────────────────────────────────────
FROM node:20.11-alpine AS runtime

# Create a non-root user
RUN addgroup -S app && adduser -S app -G app

WORKDIR /app
ENV NODE_ENV=production \
    PORT=3000

# Only what we need at runtime
COPY --from=builder --chown=app:app /app/dist ./dist
COPY --from=builder --chown=app:app /app/node_modules ./node_modules
COPY --from=builder --chown=app:app /app/package.json ./package.json

# Writable scratch for uploads (config requested this)
RUN mkdir -p /tmp/uploads && chown -R app:app /tmp/uploads

USER app
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD wget -q -O- http://localhost:3000/healthz || exit 1

CMD ["node", "dist/server.js"]
```

```
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
!.env.example
dist
coverage
*.log
.DS_Store
.vscode
.idea
README.md
Dockerfile
.dockerignore
```

Notes on choices:
- `node:20.11-alpine` chosen over `node:20`-debian for size (~50MB vs ~400MB). If you hit a native-dep build issue (e.g. canvas, sharp), switch to `node:20.11-slim`.
- Multi-stage with `npm prune --omit=dev` in the builder, then copying only built `node_modules` to runtime — slashes final image size.
- `--mount=type=cache,target=/root/.npm` speeds up rebuilds dramatically — requires BuildKit (`DOCKER_BUILDKIT=1 docker build …` or modern Docker).
- HEALTHCHECK assumes you expose `/healthz` — adjust path if your app uses something different.
- `/tmp/uploads` is in the container filesystem (ephemeral). For persistent uploads, mount a volume there at run time.
// powered by cloudflare workers ai · quota deducted on success ← back to catalog