Development

What Is a .dockerignore File? Why Docker Builds More Than You Think

Learn what a .dockerignore file is, what happens if you don't have one, how Docker builds using a build context, and why excluding unnecessary files improves security, performance and reproducibility.

What Is a .dockerignore File? Why Docker Builds More Than You Think

A .dockerignore file tells Docker which files and directories to leave out of a build context.

That matters because docker build does not treat every file in your working directory as automatically available forever. Docker first determines the build context and applies ignore rules to it. Files excluded by .dockerignore are unavailable to COPY and ADD instructions that read from that context.

project directory

.dockerignore rules

build context

Dockerfile instructions

For a large repository, excluding dependencies, Git history, logs, build output, and local secrets can substantially reduce the amount of irrelevant data involved in a build.

The Build Context Is What Docker Can See

Suppose a project contains:

project/
├── src/
├── node_modules/
├── .git/
├── .env
├── logs/
├── Dockerfile
└── package.json

A .dockerignore might contain:

node_modules/
.git/
.env
logs/

Those paths are excluded from the context available to ordinary COPY and ADD operations. A later instruction such as:

COPY . .

therefore copies only files that survived the ignore rules.

This is the central idea behind .dockerignore: control the inputs available to the build. It is more precise than thinking of the file merely as a way to make images smaller.

Docker’s build context documentation describes the current context and ignore-file behavior in detail.

Smaller Contexts Can Make Builds Faster

Local dependency directories can contain tens of thousands of files. Git history, test reports, caches, and generated output can add hundreds of megabytes more.

If those files are irrelevant to the build, including them creates work with no useful result. Docker or the selected builder may need to walk, checksum, transfer, or otherwise account for context data before and during the build.

Excluding irrelevant paths reduces that input.

The effect depends on the builder and where it runs. Modern BuildKit can avoid transferring some unused files in ways older explanations of Docker builds do not capture, so it is better to think in terms of keeping the build context deliberate rather than assuming every build always uploads one giant archive to a daemon.

.dockerignore Does Not Automatically Make the Image Smaller

Build-context size and image size are different things.

Suppose node_modules/ exists locally but the Dockerfile copies only:

COPY package.json package-lock.json ./
RUN npm ci

COPY src/ ./src/

Local node_modules/ is never copied into the image. Ignoring it can still reduce unnecessary context processing, but it may not change the final image size.

Now consider:

COPY . .

If node_modules/ remains in the context, that broad copy can put it into the image. Excluding the directory can then affect both the context and the resulting image.

The useful question is therefore: does this file need to be available to this build?

Ignore Sensitive Local Files Before the Build

Development directories often contain .env files, credentials, private keys, cloud configuration, and other data that should not become build inputs.

A .dockerignore can keep those files out of the context:

.env
.env.*
*.pem

This reduces the chance that a broad COPY instruction or an unexpected build step exposes them.

It is still only one protection. Secrets that the build genuinely needs should use an appropriate secret-management mechanism rather than being copied into the context and deleted later. Docker BuildKit, for example, supports secret mounts for build-time secrets.

Patterns Decide What Stays Out

Each line in .dockerignore is a pattern. Common rules include:

node_modules/
.git/
coverage/
dist/
*.log
.env
.vscode/
.idea/

Docker also supports exceptions with !:

*.md
!README.md

The second rule makes README.md available again after the broader Markdown rule excluded matching files. Rule order matters when exclusions and exceptions overlap.

Docker’s matching behavior has details beyond ordinary shell globs, so unusual patterns are worth checking against the official syntax documentation.

A Practical File Should Match the Dockerfile

There is no universal .dockerignore that should be copied into every repository. The file has to agree with what the Dockerfile actually needs.

For a typical Node.js project, a starting point might be:

node_modules/
.git/
coverage/
dist/
*.log
.env
.vscode/
.idea/

If the Dockerfile contains:

COPY package.json package-lock.json ./

both package files must remain in the context. If an ignore rule removes one of them, the build cannot copy it.

The same principle applies to generated files. If the container build creates dist/ itself, excluding the local copy is sensible. If the Dockerfile expects a prebuilt dist/, excluding it breaks the build.

The goal is not the smallest possible context. It is the smallest context that still contains the required inputs.

.dockerignore and .gitignore Control Different Boundaries

The files look similar but serve different tools.

FileControls
.dockerignoreFiles available in a Docker build context
.gitignoreUntracked files Git normally leaves out of version control

A file ignored by Git can still enter a Docker build context. A file ignored by Docker can still be committed to Git.

That distinction is especially important for secrets. Putting .env in .gitignore helps prevent an untracked local file from being added to Git accidentally; it does not by itself prevent docker build from seeing the file.

Dockerfile-Specific Ignore Files Are Also Supported

Projects with several Dockerfiles can provide rules for each one. Docker supports files named after the Dockerfile with the .dockerignore suffix:

Dockerfile
.dockerignore

build.Dockerfile
build.Dockerfile.dockerignore

test.Dockerfile
test.Dockerfile.dockerignore

When a Dockerfile-specific ignore file is used, its rules take precedence over the root .dockerignore for that Dockerfile. This is useful when production, test, and build images genuinely need different context inputs.

Treat the Context as an Input Boundary

A good .dockerignore is usually short because most projects have only a few categories of local files that should never participate in a container build: dependencies installed during the build, repository metadata, editor state, logs, temporary output, local secrets, and generated artifacts that the build recreates.

Review the file when the Dockerfile or project layout changes. An ignore rule that was correct six months ago can become wrong after a build starts depending on a new file.

The simplest test remains the most useful one: if Docker cannot see this path, can the build still produce the intended image? If yes, excluding it keeps the build input smaller and more deliberate.

Top