Docker Init: Generate Dockerfiles Automatically
Learn how to use docker init to scaffold Dockerfiles, Compose files, and .dockerignore for your projects in seconds. Supports Node.js, Python, Go, Rust, and more.
What you'll learn
- ✓What docker init does and why it exists
- ✓How to scaffold Dockerfiles for various languages
- ✓Customizing generated files for production use
- ✓Integrating docker init into your development workflow
Prerequisites
- •Docker Desktop 4.18+ or Docker Engine with CLI plugins
- •Basic understanding of Dockerfiles
If you have ever copied the same Dockerfile boilerplate from project to project, you know the pain. Getting the base image right, setting up multi-stage builds, configuring the correct working directory, and writing a proper .dockerignore all take time. The docker init command solves this by generating production-ready Docker configuration files tailored to your project.
What Is Docker Init?
docker init is a CLI command introduced in Docker Desktop 4.18 that detects your project’s language and framework, then scaffolds a Dockerfile, compose.yaml, and .dockerignore with best practices baked in. It supports Node.js, Python, Go, Rust, Java, and generic projects out of the box.
Think of it as npm init or cargo init, but for your container setup. Instead of hunting through documentation for the right base image or copy-pasting from Stack Overflow, you answer a few interactive prompts and get files you can actually ship.
Getting Started with Docker Init
First, verify that you have a compatible version of Docker installed:
docker --version
# Docker version 27.x or later recommended
docker init --help
Navigate to your project root and run the command:
cd /path/to/your/project
docker init
Docker inspects your project directory, detects the language, and presents an interactive wizard:
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with
sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
Let's get started!
? What application platform does your project use?
> Node
Go
Python
Rust
ASP.NET Core
PHP with Apache
Java
Other
Select your platform and answer the follow-up questions. For a Node.js project, it asks about the Node version, package manager, entry point, and port.
Example: Scaffolding a Node.js Project
Suppose you have a simple Express application. Running docker init and selecting Node generates these files:
Generated Dockerfile:
# syntax=docker/dockerfile:1
ARG NODE_VERSION=20.11.0
FROM node:${NODE_VERSION}-alpine AS base
WORKDIR /usr/src/app
FROM base AS deps
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci --omit=dev
FROM base AS build
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci
COPY . .
RUN npm run build
FROM base AS final
ENV NODE_ENV=production
USER node
COPY package.json .
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY --from=build /usr/src/app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]
Notice the multi-stage build, cache mounts for npm, non-root user, and production-only dependencies. These are all best practices that many developers skip when writing Dockerfiles from scratch.
Generated compose.yaml:
services:
server:
build:
context: .
ports:
- "3000:3000"
environment:
NODE_ENV: production
Generated .dockerignore:
node_modules
npm-debug.log
Dockerfile*
docker-compose*
compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
Example: Scaffolding a Python Project
For a Python Flask or FastAPI application:
docker init
# Select: Python
# Python version: 3.12
# Port: 8000
# Entry command: gunicorn app:app --bind 0.0.0.0:8000
Generated Dockerfile:
# syntax=docker/dockerfile:1
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}-slim AS base
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
RUN --mount=type=cache,target=/root/.cache/pip \
--mount=type=bind,source=requirements.txt,target=requirements.txt \
pip install --no-cache-dir -r requirements.txt
USER appuser
COPY . .
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
The Python template includes a dedicated non-root user with no home directory, pip cache mounts, and environment variables to prevent .pyc files and enable unbuffered output.
Example: Scaffolding a Go Project
Go projects get a particularly clean output because Go compiles to a static binary:
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.22
FROM golang:${GO_VERSION} AS build
WORKDIR /src
RUN --mount=type=cache,target=/go/pkg/mod/ \
--mount=type=bind,source=go.sum,target=go.sum \
--mount=type=bind,source=go.mod,target=go.mod \
go mod download -x
RUN --mount=type=cache,target=/go/pkg/mod/ \
--mount=type=bind,target=. \
CGO_ENABLED=0 go build -o /bin/server .
FROM gcr.io/distroless/static-debian12 AS final
COPY --from=build /bin/server /bin/
EXPOSE 8080
ENTRYPOINT ["/bin/server"]
The final stage uses a distroless image, which has no shell, no package manager, and a minimal attack surface. The resulting image is typically under 20 MB.
Customizing the Generated Files
The generated files are a starting point, not a locked configuration. Here are common customizations you should consider.
Adding Health Checks
The generated Dockerfile does not include a HEALTHCHECK instruction. Add one for production readiness:
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD ["wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"]
Adding Development Services to Compose
Extend the generated compose.yaml with databases and caches:
services:
server:
build:
context: .
ports:
- "3000:3000"
environment:
NODE_ENV: production
DATABASE_URL: postgres://user:pass@db:5432/myapp
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
timeout: 5s
retries: 5
volumes:
pgdata:
Tuning the .dockerignore
Add project-specific exclusions:
# Test files
__tests__
*.test.js
coverage/
# IDE files
.vscode/
.idea/
# Environment files
.env*
!.env.example
Non-Interactive Mode
For CI/CD pipelines or scripted setups, you can skip the interactive prompts by pre-answering questions. While docker init does not have full non-interactive flags for every option yet, you can pipe answers or use it in combination with template overrides.
A practical approach for automation is to run docker init once, commit the generated files, and then customize them in version control:
# Generate once
docker init
# Commit the scaffolded files
git add Dockerfile compose.yaml .dockerignore
git commit -m "chore: scaffold Docker configuration with docker init"
# Customize and iterate
When to Use Docker Init vs Writing From Scratch
Use docker init when:
- You are starting a new project and want best-practice defaults fast.
- You are containerizing an existing application for the first time.
- You want to audit your current Dockerfile against recommended patterns.
- You are onboarding team members who are not familiar with Docker.
Write from scratch when:
- Your project has unusual build requirements that no template covers.
- You need fine-grained control over every layer from the start.
- You are working with a language or framework not yet supported by docker init.
Common Issues and Fixes
“docker init” command not found: Make sure you are running Docker Desktop 4.18+ or have the docker-init CLI plugin installed. On Linux without Docker Desktop, you may need to install the plugin separately.
Wrong language detected: If your project has multiple languages (for example, a Go backend with a React frontend), docker init may pick the wrong one. Select the correct platform manually from the menu or run it in a subdirectory.
Generated file conflicts: If a Dockerfile or compose.yaml already exists, docker init warns you before overwriting. Back up your current files first if you want to compare.
Wrapping Up
docker init removes the friction of writing Docker configuration files from scratch. It generates multi-stage Dockerfiles with cache mounts, non-root users, and production-ready defaults for all major languages. The generated files are a solid starting point that you should customize for your specific needs, adding health checks, development services, and environment-specific configuration as your project grows. Next time you start a new project or containerize an existing one, run docker init before reaching for your old boilerplate.
Related articles
- Docker Docker vs Podman: Which Container Runtime to Use
Compare Docker and Podman on architecture, security, compatibility, and developer experience. Learn which container runtime fits your workflow in 2026.
- Docker Dockerfile Best Practices
Write production-ready Dockerfiles: layer caching, multi-stage builds, .dockerignore, security hardening, slim base images, and patterns that keep builds fast and images small.
- Docker Docker Build Context and .dockerignore Tips
Why your Docker builds are slow and your images are bloated, and how to fix both with a tight build context and a thoughtful .dockerignore.
- Docker Docker Compose Network Aliases Tutorial
Network aliases let containers reach each other under multiple names. Learn how aliases work in Compose, when to use them, and the gotchas to avoid.