sehaj/learn
Docker/02 Images

02.03 · with code · 9 min

Build context and .dockerignore

What docker build actually sends to the builder, why it was 26 MB for a one-file app, and how .dockerignore keeps secrets and junk out of your image.

The core idea

The . at the end of docker build -t notes-api . is the build context: a folder whose files the builder is allowed to see. COPY and ADD can only read from it. Everything in that folder is a candidate to end up in your image, unless a .dockerignore file says otherwise.

Why the builder needs a context

The builder (BuildKit) isn't necessarily your machine. With Docker Desktop it runs inside a VM; in CI it might be a remote server. So docker build sends the files it needs from your folder over to the builder, and that transfer is the "transferring context" line you saw in the last two lessons.

Without a .dockerignore, the notes API sends this:

❯terminal
$ docker build -t notes-api .
#5 transferring context: 26.18MB 0.2s done
$ du -sh node_modules dist src
26M node_modules
4.0K dist
4.0K src

Nearly all of it is node_modules from your own npm install, which the image doesn't even want: it runs npm ci itself, for its own platform.

.dockerignore

A .dockerignore sits next to the Dockerfile and uses patterns like .gitignore:

.dockerignore
node_modules
dist
.git
.env
*.log
Dockerfile
.dockerignore

The same build, from a clean cache:

❯terminal
$ docker build -t notes-api .
#4 transferring context: 3.88kB done

From 26 MB to under 4 kB, and the COPY . . layer shrinks from 26.9 MB to 32.8 kB.

Predict first

Your project has a .env file with a database password. The Dockerfile has COPY . . and there's no .dockerignore. You never reference .env anywhere. Is the password in the image?

Commit to an answer before you read on.

That quiz isn't hypothetical. With the first Dockerfile and no .dockerignore:

❯terminal
$ echo "SECRET=hunter2" > .env
$ docker build -t notes-api .
$ docker run --rm notes-api cat .env
SECRET=hunter2

Once an image with a secret is pushed, rotating the secret is the only real fix. Deleting the file in a later layer doesn't remove it from the earlier one (02.02 Layers and the build cache).

What to put in .dockerignore

IgnoreWhy
node_modules, vendor, .venvThe image installs its own, for its own OS and CPU.
build output: dist, build, targetThe image builds its own; stale copies cause confusion.
.gitLarge, and it changes on every commit, which busts the cache.
.env, keys, credentialsSecrets must never enter a layer.
Dockerfile, .dockerignore, *.md, testsNot needed at runtime; changing them shouldn't invalidate COPY . ..

You can also flip it around: ignore everything, then allow only what you need.

.dockerignore
*
!package.json
!package-lock.json
!tsconfig.json
!src/

This allow-list style is stricter: a new secret file in the project can't leak by accident.

CheckpointMeasure your context

Build the notes API without a .dockerignore and note the "transferring context" size. Add the file above, prune the build cache, build again, and compare. Then add a .env, build, and confirm with docker run --rm notes-api ls -a that it's no longer in the image.

STUCK? ▸

BuildKit only resends files that changed since the last build, so a second run can show a tiny number either way. Run docker builder prune -af before each build to measure from scratch.

Recap

Interview questions

JuniorfreqMust-knowConcept

What is the Docker build context, and why does .dockerignore matter?

SeniorfreqMust-knowScenario

Someone pushed an image that contains a .env file with production credentials. What do you do?

Report a mistakeEdit this page

Fundamentals you'll use

Used in

☰ Images02.03 · 9/44next →