Direct Answer
When Matplotlib cannot write to its default font cache directory, it emits a warning and rebuilds the font list in memory on each import. The supported mechanism to redirect the cache is the MPLCONFIGDIR environment variable, which must be set before the first import of matplotlib.
Confirmed Behavior vs. Likely Explanation
Confirmed: Matplotlib stores font metadata in a platform-specific cache directory (for example, ~/.cache/matplotlib on Linux). The cache file follows the pattern fontlist-v<major>.json, so caches are not portable across major versions. The MPLCONFIGDIR variable relocates the entire configuration directory, including this cache.
Likely: If the cache directory is read-only, Matplotlib falls back to scanning system font directories on every startup. This increases import latency, though the exact cost depends on the number of installed fonts and the base image. The library does not crash; it degrades to repeated discovery.
Steps for Read-Only Containers
- Set
MPLCONFIGDIR to a writable path before launching Python. In containers, /dev/shm/mpl-config provides a tmpfs-backed location that lives only for the container lifetime.
- Pre-warm the cache during the image build by importing
matplotlib once with that variable set. The generated fontlist-v*.json can then be mounted read-only at runtime.
- If the runtime environment mounts the cache as read-only, ensure the build and runtime font sets match; otherwise Matplotlib will detect the mismatch and re-scan.
Verification
MPLCONFIGDIR=/tmp/mpl-test python -c "import matplotlib; print(matplotlib.get_configdir())" confirms redirection.
ls $MPLCONFIGDIR/fontlist-*.json verifies the cache file exists.
docker run --read-only -e MPLCONFIGDIR=/dev/shm/mpl your-image python -c "import matplotlib" tests the read-only path.
Caveats
MATPLOTLIBRC points to a configuration file, not the cache directory.
- Minimal images (Alpine, distroless) may lack
fontconfig; font discovery can silently return only the bundled DejaVu Sans.
- Version assumption: cache naming changed around Matplotlib 3.7 (
fontlist-v300.json). A cache built on one major version will not be reused by another.
Diagnostic Question
Does your runtime image include fontconfig and the same system fonts as the build stage? If not, pre-building the cache will not prevent re-scanning.