Skip to content
Go back

The .dockerignore File You're Not Writing

By SumGuy 4 min read
The .dockerignore File You're Not Writing

Most Docker setups are shipping 500MB of garbage to the daemon. You’re not alone—this is the default state of things. The culprit? You don’t have a .dockerignore file, or it’s terrible.

Here’s what happens without one: docker build . sends your entire build context to the Docker daemon. That means every .git folder, node_modules, test files, markdown docs, IDE config, CI logs, and random junk you’ve accumulated. This context balloons your build, slows down the transfer to your daemon, and—here’s the kicker—can expose secrets if you’re not careful.

Why This Matters

Let’s say you have a 200MB node_modules folder, a 300MB .git history, and some .env files lying around. When you run docker build, the daemon receives all of it. Even though your Dockerfile only copies COPY package.json . and maybe COPY src ./src, Docker still has to parse the entire context to figure out what changed for layer caching. Slow builds. Wasted bandwidth.

Worse: if you’re running this in CI, you’re uploading secrets and sensitive config to the build machine every single time.

The Fix: A Bulletproof .dockerignore

Create a .dockerignore file in your project root (same level as your Dockerfile) and copy this in:

.dockerignore
# Version control
.git
.gitignore
.gitattributes
# Node.js (if you use it)
node_modules
npm-debug.log
yarn-error.log
package-lock.json
yarn.lock
# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env/
venv/
pip-log.txt
# Environment and secrets
.env
.env.local
.env.*.local
.aws
.ssh
# IDE and editor garbage
.vscode
.idea
*.swp
*.swo
*~
.DS_Store
.sublime-project
.sublime-workspace
# Build artifacts and temp files
build/
dist/
*.o
*.a
*.so
.cache
tmp/
temp/
# CI/CD
.github
.gitlab-ci.yml
.circleci
Jenkinsfile
# Documentation
docs/
README.md
CHANGELOG.md
LICENSE
*.md
# Testing
test/
tests/
.test
.coverage
coverage/
htmlcov/
# Docker
Dockerfile
docker-compose.yml
docker-compose.*.yml
.dockerignore

This is a kitchen-sink version. You won’t use all of it, but it covers most languages and patterns. Trim it to your project.

How to Customize It

Start with the template above, then remove lines for things you do need in the container. For example:

Python web app — You might want docs in the image, so remove docs/ and README.md:

docs/
# Remove these lines from the template
# README.md

Node.js app — You probably want to keep .git out but can remove the Python stuff:

venv/
# Remove from template
# __pycache__
# *.pyc
# etc.

Go binary — Most Go apps need almost nothing:

.dockerignore
.git
.gitignore
.env
.env.local
.vscode
.idea
.DS_Store
test/
tests/
README.md
docs/
Dockerfile
docker-compose.yml

Real-World Impact

Let’s quantify this. Suppose you have:

Without .dockerignore: Docker daemon receives 600MB. Layer caching checks everything. Build takes 15 seconds to send context alone.

With .dockerignore: Docker daemon receives 50MB (just your source). Build context sent in 1 second. Layer caching is faster. Same build, 10x quicker.

And you’re not exposing .env or .aws credentials to the build machine.

Pro Tips

  1. Test your .dockerignore: Run docker build --no-cache and watch the output. It’ll tell you what’s being sent:
Terminal window
$ docker build -t myapp:v1 .
Sending build context to Docker daemon 2.048kB # ← This should be small
  1. Use .dockerignore in your CI: If .dockerignore isn’t checked in (and it should be), CI machines won’t respect it. Check it in.

  2. Don’t ignore what you COPY: If your Dockerfile does COPY . ., make sure you’re not ignoring files you actually need.

  3. Secrets should never be in the build: Use build arguments or secret mounts instead of relying on .dockerignore:

Dockerfile
FROM node:18
WORKDIR /app
COPY package.json .
RUN --mount=type=secret,id=npm npm ci
COPY . .
RUN npm run build
CMD ["npm", "start"]

Build with: docker build --secret npm=~/.npmrc .

Checklist

A .dockerignore file takes 2 minutes to write once and saves you thousands of seconds over your project’s lifetime. Your future self will thank you.

Verify Your Context Size

After setting up .dockerignore, confirm the build context is actually smaller:

Terminal window
# Before and after comparison
docker build --no-cache . 2>&1 | grep "Sending build context"

You should see something like:

Sending build context to Docker daemon 1.234kB

If it’s still showing megabytes and you expected kilobytes, something’s not in your .dockerignore. The --no-cache flag ensures you’re not seeing a cached result.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it may appear here.


Previous Post
CPU and I/O Priority with nice and ionice
Next Post
Linux File Descriptor Limits: When 1024 Isn't Enough

Related Posts