#16540·nix

Ccache stdenv is slow, and new contributor documentatioon

Author: MaxistheSpyCreated Sep 30, 2026Updated Sep 30, 2026

Ccache stdenv is referened in the building doc as a way to get much faster builds. It looks to me like this was put there before the switch to ninja/meson which does a lot of optimization on that front and now its advantage is vastly overstated https://github.com/NixOS/nix/pull/7082. Currently the clangd builds >2x faster and doesnt seem to lose out to ccache unless i completely delete and rebuild the build directory. whats more ccache stdenv breaks LSP support in the way it wraps the compile commands.

I did look less rigorously at the difference for single file changes and didnt see a notable difference. the main difference lies in the case where we fully rebuild clangstdenv first build, ~ equivalent for full wipe and rebuild:

-build
real    1m49.037s
user    47m49.379s
sys     1m24.789s

ccache first build:

ccache no changes build directory deleted and rebuilt:

-build
real 4m15.116s
user 112m55.346s
sys 8m6.277s
rm -rf ./build
-build
real 0m6.201s
user 0m20.409s
sys 0m16.264s

we do definitely see performance increases from complete rebuilds with no flag changes but im not sure this workflow is all that common. are people regularly deleting ./build vs rebuilding from scratch.

In general id like to streamline and standardize the build instructions for new contributors being one myself it was confusing enough to get things setup.I have a lot of thoughts but they are out of scope for this issue

assisted-by: commands were partially generated by llms then modified by me

full test results below.

``` Anyway here are the timings for ccache vs std. I have a pretty maxed out desktop pc to build on so this is probably on the faster side of real world. nix-shell --attr devShells.x86_64-linux.native-clangStdenv --run ' export NIX_BUILD_CORES="$(nproc)" export CCACHE_DIR="$PWD/.bench-ccache"; rm -rf "$CCACHE_DIR" build export dontAddPrefix=1

quiet PHASE: hide output while it succeeds; dump the log only on failure

quiet() { local log="$PWD/.quiet.log" status if "$@" >"$log" 2>&1; then :; else status=$? echo "--- $* failed (exit $status); dumping log ---" >&2 cat "$log" >&2 return "$status" fi }

echo "== clangStdenv: cold ==" rm -rf build; time quiet configurePhase; time quiet buildPhase; time quiet checkPhase; cd ..; echo "== clangStdenv: wiped dir, rebuild ==" rm -rf build; time quiet configurePhase; time quiet buildPhase; time quiet checkPhase; ' == clangStdenv: cold == -configure real 0m30.707s user 0m14.777s sys 0m16.078s -build real 1m49.037s user 47m49.379s sys 1m24.789s -check real 0m28.839s user 3m25.749s sys 2m3.773s == clangStdenv: wiped dir, rebuild == -configure real 0m30.507s user 0m14.711s sys 0m15.937s -build real 1m48.367s user 47m47.201s sys 1m24.249s -check real 0m28.485s user 3m26.502s sys 2m6.424s

nix-shell --attr devShells.x86_64-linux.native-ccacheStdenv --run ' export NIX_BUILD_CORES="$(nproc)" export CCACHE_DIR="$PWD/.bench-ccache"; rm -rf "$CCACHE_DIR" build export dontAddPrefix=1

quiet PHASE: hide output while it succeeds; dump the log only on failure

quiet() { local log="$PWD/.quiet.log" status if "$@" >"$log" 2>&1; then :; else status=$? echo "--- $* failed (exit $status); dumping log ---" >&2 cat "$log" >&2 return "$status" fi }

echo "== ccacheStdenv: cold ==" rm -rf build; time quiet configurePhase; time quiet buildPhase; time quiet checkPhase; cd ..; echo "== ccacheStdenv: wiped dir, rebuild ==" rm -rf build; time quiet configurePhase; time quiet buildPhase; time quiet checkPhase; '

Using pytestCheckPhase == ccacheStdenv: cold == -configure

real 0m28.174s user 0m13.600s sys 0m14.736s

real 4m15.116s user 112m55.346s sys 8m6.277s

real 0m28.941s user 3m21.683s sys 2m5.695s == ccacheStdenv: wiped dir, rebuild == -configure real 0m28.357s user 0m13.538s sys 0m15.005s -build real 0m6.201s user 0m20.409s sys 0m16.264s

real 0m23.475s user 3m12.876s sys 2m4.714s

</details>