Run apt-get update and apt-get install in the same RUN instruction, install only the packages you name, and remove the package lists in that same step. This keeps the layer small, avoids stale package indexes from the build cache, and leaves fewer tools in the image for an attacker to use.
The one rule Docker spells out
Docker's best practices page says to always combine the update command with the install command in the same RUN statement. The reason is the build cache. If update sits in its own layer, Docker may reuse that cached layer weeks later, and the next install step then works from an old package index. You get older versions than you expect, sometimes with known flaws.
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
Why remove the package lists
The same page notes that removing the apt lists directory reduces image size, because the cache is not stored in a layer. It also says the official Debian and Ubuntu images already run a clean step, so the explicit removal matters less there. Keep it anyway if you build on other bases. It costs one line and makes the intent obvious to reviewers.
The cleanup must happen in the same RUN step as the install. If you delete the lists in a later instruction, the files still exist in the earlier layer and the image does not shrink.
Skip the recommended extras
Apt installs recommended packages by default. The no-install-recommends option tells it to install only what you asked for and the hard dependencies. Docker's own examples use it. Fewer packages means less to patch and fewer binaries a scanner will flag. Test your image after adding it, because some programs quietly relied on a recommended package.
Should you pin package versions?
Docker describes version pinning as a way to bust the cache and force a specific version. The tradeoff is upkeep. A pinned version that leaves the archive makes the build fail, and a pin you never update freezes known flaws in place. Many teams pin the base image and rebuild often instead of pinning each apt package. Pick one approach and write down who updates it.
| Choice | Benefit | Cost |
|---|---|---|
| Combine update and install | No stale index | None |
| Remove apt lists in same step | Smaller layer | One extra line |
| Skip recommended packages | Fewer packages to patch | Occasional missing library |
| Pin each package version | Repeatable builds | Frequent pin updates |
Check the result
After the build, list what you shipped. A scan of the built image shows the operating system packages and their known flaws, and a rebuild with a fresh base shows how many disappear. See scanning a local image before you push it and rebuilding images regularly.
Try it yourself
Click through it at your own pace, or open it full screen.
Quick check
Does cleaning apt lists in a later RUN shrink the image?
No. Layers are additive, so the files remain in the earlier layer. Clean up in the same RUN step that created them.
Is apt-get update on its own line a security problem?
It can be. A cached update layer leaves later installs using an old index, so you may ship older packages than you intended.
Safeguard
Safeguard does SBOM and dependency scanning, and its policies and gates can run in CI so a bad image does not reach production. You can try a free scan before deciding anything.
Sources
Last reviewed: 19 October 2026.