Skip to main content

whycache

Docker tells you that the build cache broke. whycache tells you why, which file did it, and what it cost you.

whycache explaining an 11-minute cache miss in psf/black

That is a real run against psf/black. Every commit costs an eleven-minute rebuild, because COPY . /src/ pulls in .git, which changes on every commit, and the expensive apt install + pip install + hatch build steps all sit below it.

Nobody on that project is doing anything wrong. It is simply invisible — Docker prints which steps re-ran, never why.


Install

pip install whycache

Or from source, until the first PyPI release lands:

git clone https://github.com/allaboutaryan/whycache && pip install ./whycache

No daemon, no account, no config, no network calls. One dependency-free CLI.

Use

whycache                       # build the current directory
whycache path/to/project       # or somewhere else
whycache . -- --build-arg V=2  # anything after -- goes to docker build

Run it once to record a baseline, then run it again after you change something.

What it tells you

A file changed. Which one, and only the ones that instruction actually copies:

X Cache broke at build step 10:  COPY src ./src

  Reason - 1 file(s) changed in the build context:

    src/sqlfluff/api/info.py

  Cost - 7.5s of this 7.5s build.

A build arg changed. Docker substitutes args into the command before caching it, so the change is visible if you know where to look:

X Cache broke at step 2:  RUN echo "building 3.0.0" > /version

  Reason - the instruction itself changed since the last build:

    was:  RUN echo "building 2.0.0" > /version
    now:  RUN echo "building 3.0.0" > /version

Junk is polluting your build context. With a concrete fix:

  Fix - add to .dockerignore:
    .git/                  (changes on every commit, 2 file(s))
    node_modules/          (reinstallable from lockfile, 41 file(s))

  Saves ~4m12s per build.

...unless that fix would break your build. black derives its version from git via hatch-vcs, so ignoring .git/ does not make the build slower — it makes it fail:

  .git/ is breaking the cache (1 file(s)), but do NOT ignore it:
    pyproject.toml reads git metadata at build time, so excluding
    .git/ makes the build fail rather than just slow.

This one is not hypothetical. An earlier version of this tool gave that advice, and broke black's build with it.

The number tells you if your Dockerfile is well built

Same tool, three real projects:

Project What changed Cache broke at Cost
psf/black one commit COPY . /src/ (step 3 of 6) 11m00s
sqlfluff one source file COPY src ./src (step 10 of 12) 7.5s
traefik/whoami go.mod COPY go.mod . (step 4) 30.2s
traefik/whoami app.go COPY . . (step 7) 29.6s

A miss high in the Dockerfile is expensive because everything below it re-runs. A miss near the bottom is cheap. That gap is the entire skill of writing a Dockerfile, and this is what makes it visible.

How it works

  1. Runs your build with --progress=rawjson and reads the structured output.
  2. Finds the first step that was not CACHED.
  3. Fingerprints your build context, honouring .dockerignore, and diffs it against the last run.
  4. Sums the time of every step that re-ran.

State lives in ~/.whycache/, keyed by project path. Nothing is written into your build context — doing that would change the context and break the cache, which is the exact problem this tool exists to report.

What it will not do

  • It will not edit your Dockerfile. It tells you; you decide.
  • It will not guess. If the cache was cold, or the cause is outside the build context, it says so and names no file. A confidently wrong answer is worse than no answer, so it declines rather than blames.
  • No AI. This is a deterministic diff of two file lists. An LLM would make it slower, costlier, and less trustworthy.

How it compares

Tool Answers
dive How much space is wasted in the image
hadolint Does the Dockerfile follow style rules
whycache Why the cache missed on this build, and what it cost

Different questions. dive and hadolint are both excellent; neither answers this one.

Requirements

  • Docker with BuildKit (the default since Docker 23)
  • Python 3.10+

Works on Linux, macOS, and Windows. It is developed on Windows, so the console output degrades to ASCII rather than crashing on cp1252 — a courtesy most Linux-first tooling forgets.

Overhead

Fingerprinting a 5,955-file / 25 MB context takes ~730 ms on a warm run, because unchanged files are never reopened. First run on a project costs ~6 s.

Contributing

Bug reports with a Dockerfile that reproduces are the most useful thing you can send. The test suite runs without Docker except for test_e2e.py:

python test_dockerignore.py    # .dockerignore matching
python test_whycache.py        # step parsing, blame, git-versioning guard
python -m whycache.manifest    # context fingerprinting
python test_e2e.py             # full run against a real build (needs Docker)

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

whycache-0.1.0.tar.gz (19.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

whycache-0.1.0-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file whycache-0.1.0.tar.gz.

File metadata

  • Download URL: whycache-0.1.0.tar.gz
  • Upload date:
  • Size: 19.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for whycache-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9c55a0dcd63ad9a734e5647d703097053c812972b418af74021a279b01c8bb04
MD5 cd5b6833e97d4322d7ffffb449b5250a
BLAKE2b-256 f9dc2aa19ae2d8ab8fda32b86ef4f462bb4a1a68aa1ae777c2dda18e99e41aed

See more details on using hashes here.

File details

Details for the file whycache-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: whycache-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for whycache-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c8de393e46ccc5c9ad29d3de928c19dddb06a29681253f4a4807ea21253129cc
MD5 2d042f5d0e00a6be6e8461209178a102
BLAKE2b-256 37ba8f9092971528bf1f77fd5b4e727d129a9be6f5def3cb9ef82ed66f6ff09e

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page