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:
$ docker build -t notes-api .#5 transferring context: 26.18MB 0.2s done$ du -sh node_modules dist src26M node_modules4.0K dist4.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:
node_modules
dist
.git
.env
*.log
Dockerfile
.dockerignoreThe same build, from a clean cache:
$ 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.
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?
That quiz isn't hypothetical. With the first Dockerfile and no .dockerignore:
$ echo "SECRET=hunter2" > .env$ docker build -t notes-api .$ docker run --rm notes-api cat .envSECRET=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
| Ignore | Why |
|---|---|
node_modules, vendor, .venv | The image installs its own, for its own OS and CPU. |
build output: dist, build, target | The image builds its own; stale copies cause confusion. |
.git | Large, and it changes on every commit, which busts the cache. |
.env, keys, credentials | Secrets must never enter a layer. |
Dockerfile, .dockerignore, *.md, tests | Not needed at runtime; changing them shouldn't invalidate COPY . .. |
You can also flip it around: ignore everything, then allow only what you need.
*
!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.
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
What is the Docker build context, and why does .dockerignore matter?
Someone pushed an image that contains a .env file with production credentials. What do you do?