20.2.2.1 Dockerignore Practice
A focused guide to Dockerignore Practice, connecting core concepts with practical Docker and container operations.
The .dockerignore file controls which files and directories from the build context are sent to the Docker daemon when docker build runs. Without it, every file in the build context directory — including generated output directories, dependency caches, version control history, environment files with secrets, and large binary assets — is packaged and transferred to the daemon, even if the Dockerfile never references those files. A well-crafted .dockerignore reduces build time, image size, and the risk of accidentally baking sensitive files into the image.
How the Build Context Works
When you run:
docker build -t my-image .
The . tells Docker to use the current directory as the build context. Before executing any Dockerfile instruction, Docker packages every file in that directory (recursively) and sends the package to the build daemon. The .dockerignore file is processed first — files matching any pattern in it are excluded from the package before transmission.
This is important: even if a COPY . . instruction would include a file, adding it to .dockerignore prevents the daemon from ever receiving the file, so the COPY cannot include it. The exclusion happens at the context packaging stage, not at the COPY stage.
Creating the .dockerignore File
Create a file named .dockerignore in the same directory as the Dockerfile:
touch .dockerignore
On Windows (PowerShell):
New-Item .dockerignore -ItemType File
The file uses one pattern per line. Docker's pattern syntax is similar to .gitignore:
node_modules
.git
*.log
.env
dist
Patterns and Syntax
Exact name: excludes files and directories with that exact name at any depth:
.env
Excludes .env in the root and any subdirectory.
Wildcard *: matches any sequence of characters within a path segment:
*.log
*.tmp
Excludes any file ending in .log or .tmp.
Directory-specific: excludes a path only from the root:
/dist
The leading / anchors the pattern to the build context root.
Recursive glob **: matches across directory levels:
**/*.test.js
Excludes all .test.js files at any depth.
Negation !: re-includes a file that was excluded by a previous pattern:
*.md
!README.md
Excludes all Markdown files except README.md.
Standard .dockerignore for a Node.js Project
# Dependencies installed in the container, not copied from host
node_modules
# Version control — not needed in the image
.git
.gitignore
# Environment secrets — must never be baked into an image
.env
.env.*
!.env.example
# Build outputs that are generated by the build step inside the container
dist
build
coverage
# Logs
*.log
npm-debug.log*
# IDE and OS files
.DS_Store
.vscode
.idea
Thumbs.db
# Docker files themselves
Dockerfile
.dockerignore
docker-compose.yml
compose.yml
The most critical entry is node_modules. Without it, the entire node_modules directory from the host (potentially 200MB–500MB) is packaged into the build context on every build, even when RUN npm install is in the Dockerfile and will install its own dependencies inside the container.
Standard .dockerignore for a Python Project
# Virtual environment
.venv
venv
env
# Compiled bytecode
__pycache__
*.pyc
*.pyo
*.pyd
# Version control
.git
# Environment secrets
.env
*.env
# Test and coverage
.pytest_cache
htmlcov
.coverage
coverage.xml
tests
# Build outputs
dist
build
*.egg-info
# IDE
.vscode
.idea
Standard .dockerignore for a Go Project
# Version control
.git
# Build output (cross-compiled binary goes here)
bin
dist
# Test coverage
*.out
coverage.html
# IDE
.vscode
.idea
# Environment
.env
For Go, the source code must be present in the context because the build happens inside the container. The key exclusion is .git (which carries the full repository history) and any pre-built binaries from the host.
Verifying Context Size
Before and after creating .dockerignore, check the build context size. The first line of docker build output shows how much data is transferred:
Without .dockerignore:
=> [internal] load build context
=> => transferring context: 84.32MB 3.1s
After adding .dockerignore:
=> [internal] load build context
=> => transferring context: 1.24MB 0.1s
A 98% reduction in context transfer time directly translates to faster builds, especially when building remotely or in CI pipelines with limited bandwidth.
Security: Preventing Secrets from Entering Images
The most critical security use of .dockerignore is preventing .env files, credential files, and private keys from being included in an image. Even if the Dockerfile's COPY . . is followed by RUN rm .env, the file was included in the layer created by COPY and remains accessible in that layer's data. Someone who pulls the image and runs docker history or inspects the layer archive can retrieve the deleted file.
The only safe approach is to exclude secret files from the build context entirely via .dockerignore:
.env
*.pem
*.key
id_rsa
credentials.json
service-account.json
Environment variables should be passed to the container at runtime via docker run -e or env_file, not baked into the image.
The Dockerfile Itself in .dockerignore
Including Dockerfile and compose.yml in .dockerignore is a minor optimization. These files are used by the Docker CLI to read build instructions, but once read, they do not need to be included in the image. Adding them to .dockerignore prevents them from being copied into the image if COPY . . is used:
Dockerfile
.dockerignore
compose.yml
docker-compose.yml
This is optional but clean practice for production images.