---
name: create-dockerfile
locale: caveman-lite
source_locale: en
source_commit: 82c77053
translator: "Julius Brussee homage — caveman"
translation_date: "2026-04-19"
description: >
  Create general-purpose Dockerfiles for Node.js, Python, Go, Rust, and Java
  projects. Covers base image selection, dependency installation, user
  permissions, COPY patterns, ENTRYPOINT vs CMD, and .dockerignore. Use when
  containerizing an application for the first time, creating a consistent
  build/runtime environment, preparing an app for cloud deployment or Docker
  Compose, or when no existing Dockerfile is present in the project.
license: MIT
allowed-tools: Read Write Edit Bash Grep Glob
metadata:
  author: Philipp Thoss
  version: "1.0"
  domain: containerization
  complexity: basic
  language: Docker
  tags: docker, dockerfile, node, python, go, rust, java, container
---

# Create Dockerfile

Write a production-ready Dockerfile for general-purpose application projects.

## When to Use

- Containerizing a Node.js, Python, Go, Rust, or Java application
- Creating a consistent build/runtime environment
- Preparing an application for cloud deployment or Docker Compose
- No existing Dockerfile in the project

## Inputs

- **Required**: Project language and entry point (e.g., `npm start`, `python app.py`)
- **Required**: Dependency manifest (package.json, requirements.txt, go.mod, Cargo.toml, pom.xml)
- **Optional**: Target environment (development or production)
- **Optional**: Exposed ports

## Procedure

### Step 1: Choose Base Image

| Language | Dev Image | Prod Image | Size |
|----------|-----------|------------|------|
| Node.js | `node:22-bookworm` | `node:22-bookworm-slim` | ~200MB |
| Python | `python:3.12-bookworm` | `python:3.12-slim-bookworm` | ~150MB |
| Go | `golang:1.23-bookworm` | `gcr.io/distroless/static` | ~2MB |
| Rust | `rust:1.82-bookworm` | `debian:bookworm-slim` | ~80MB |
| Java | `eclipse-temurin:21-jdk` | `eclipse-temurin:21-jre` | ~200MB |

**Got:** Select the slim/distroless variant for production images.

### Step 2: Write Dockerfile (by language)

#### Node.js

```dockerfile
FROM node:22-bookworm-slim

RUN groupadd -r appuser && useradd -r -g appuser -m appuser

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --omit=dev

COPY . .

USER appuser
EXPOSE 3000
CMD ["node", "src/index.js"]
```

#### Python

```dockerfile
FROM python:3.12-slim-bookworm

RUN groupadd -r appuser && useradd -r -g appuser -m appuser

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

USER appuser
EXPOSE 8000
CMD ["python", "app.py"]
```

#### Go

```dockerfile
FROM golang:1.23-bookworm AS builder

WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/server ./cmd/server

FROM gcr.io/distroless/static
COPY --from=builder /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
```

#### Rust

```dockerfile
FROM rust:1.82-bookworm AS builder

WORKDIR /src
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src

COPY . .
RUN touch src/main.rs && cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /src/target/release/myapp /usr/local/bin/myapp
EXPOSE 8080
ENTRYPOINT ["myapp"]
```

#### Java (Maven)

```dockerfile
FROM eclipse-temurin:21-jdk AS builder

WORKDIR /src
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests

FROM eclipse-temurin:21-jre
COPY --from=builder /src/target/*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
```

**Got:** `docker build -t myapp .` completes without errors.

**If fail:** Check base image availability and dependency installation commands.

### Step 3: ENTRYPOINT vs CMD

| Directive | Purpose | Override |
|-----------|---------|----------|
| `ENTRYPOINT` | Fixed executable | Override with `--entrypoint` |
| `CMD` | Default arguments | Override with trailing args |
| Both | `ENTRYPOINT` + default args via `CMD` | Args override CMD only |

Use `ENTRYPOINT` for compiled binaries with a single purpose. Use `CMD` for interpreted languages where you might want `docker run myapp bash`.

### Step 4: Create .dockerignore

```
.git
.gitignore
node_modules
__pycache__
*.pyc
target/
.env
.env.*
*.md
!README.md
.vscode
.idea
Dockerfile
docker-compose*.yml
```

**Got:** Build context excludes development artifacts.

### Step 5: Add Non-Root User

Always run as non-root in production:

```dockerfile
RUN groupadd -r appuser && useradd -r -g appuser -m appuser
USER appuser
```

For distroless images, use the built-in nonroot user:

```dockerfile
FROM gcr.io/distroless/static:nonroot
USER nonroot
```

### Step 6: Build and Verify

```bash
docker build -t myapp:latest .
docker run --rm myapp:latest
docker image inspect myapp:latest --format '{{.Size}}'
```

**Got:** Container starts, responds on the expected port, runs as non-root.

**If fail:** Check logs with `docker logs`. Verify WORKDIR, COPY paths, and exposed ports.

## Validation

- [ ] `docker build` completes without errors
- [ ] Container starts and application responds
- [ ] `.dockerignore` excludes unnecessary files
- [ ] Application runs as non-root user
- [ ] Dependencies are copied before source code (cache efficiency)
- [ ] No secrets or `.env` files baked into the image

## Pitfalls

- **COPY before dependency install**: Invalidates the dependency cache on every code change. Always copy the manifest file first.
- **Running as root**: Default Docker user is root. Always add a non-root user for production.
- **Missing .dockerignore**: Sending `node_modules` or `.git` into the build context wastes time and disk.
- **Using `latest` tag for base images**: Pin to specific versions (e.g., `node:22.11.0`) for reproducibility.
- **Forgetting `--no-cache-dir`**: Python `pip` caches packages by default, bloating the image.
- **ADD vs COPY**: Use `COPY` unless you need URL download or tar extraction (`ADD` auto-extracts).

## Related Skills

- `create-r-dockerfile` - R-specific Dockerfile using rocker images
- `create-multistage-dockerfile` - multi-stage patterns for minimal production images
- `optimize-docker-build-cache` - advanced caching strategies
- `setup-compose-stack` - orchestrate the containerized app with other services
