diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml
index f739d8f125b2c97c87d9147b9689a33d321ea52d..084f15fe40b6f714c6fdfcdd46cb03b3eac76a0d 100644
--- a/.github/workflows/benchmarks.yml
+++ b/.github/workflows/benchmarks.yml
@@ -14,6 +14,10 @@ jobs:
         CC:  gcc-11
         CXX: g++-11
     steps:
+      - name: Get build dependencies
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y ninja-build ccache
       - name: Set up cmake
         uses: jwlawson/actions-setup-cmake@v1.13
         with:
@@ -22,12 +26,25 @@ jobs:
         uses: actions/checkout@v3
         with:
           submodules: recursive
+      # figure out vector extensions for ccache key
+      - name: Check vector extensions
+        run: |
+          HAS_AVX512F=$([[ $(lscpu | grep "avx512f" | wc -l) -eq 1 ]] && echo "_avx512f" || echo "")
+          HAS_AVX2=$([[ $(lscpu | grep "avx2" | wc -l) -eq 1 ]] && echo "_avx2" || echo "")
+          HAS_FMA=$([[ $(lscpu | grep "fma" | wc -l) -eq 1 ]] && echo "_fma" || echo "")
+          HAS_AVX=$([[ $(lscpu | grep "avx" | wc -l) -eq 1 ]] && echo "_avx" || echo "")
+          VECTOR_EXTENSIONS=${HAS_AVX512F}${HAS_AVX2}${HAS_FMA}${HAS_AVX}
+          echo "VECTOR_EXTENSIONS=$VECTOR_EXTENSIONS" >> $GITHUB_ENV
+      - name: Setup ccache
+        uses: hendrikmuhs/ccache-action@v1.2
+        with:
+          key: benchmarks-${{ env.CXX }}-${{ env.VECTOR_EXTENSIONS }}
       - name: Build arbor
         run: |
           mkdir build
           cd build
-          cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_MPI=OFF -DARB_USE_BUNDLED_LIBS=ON
-          make -j4 ubenches
+          cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_MPI=OFF -DARB_USE_BUNDLED_LIBS=ON
+          ninja -j4 ubenches
           cd -
       - name: Run benchmarks
         run: |
diff --git a/.github/workflows/sanitize.yml b/.github/workflows/sanitize.yml
index 583cfe57afa2c3820c3058973e83d1984b329e14..788e5d219aca87cfb8659ac3a371dd2beb0502de 100644
--- a/.github/workflows/sanitize.yml
+++ b/.github/workflows/sanitize.yml
@@ -19,6 +19,10 @@ jobs:
         CXX:          clang++-14
         ASAN_OPTIONS: detect_leaks=1
     steps:
+      - name: Get build dependencies
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y ninja-build ccache
       - name: Set up cmake
         uses: jwlawson/actions-setup-cmake@v1.13
         with:
@@ -29,13 +33,27 @@ jobs:
           submodules: recursive
       - name: Update pip
         run: python -m pip install --upgrade pip
+      # figure out vector extensions for ccache key
+      - name: Check vector extensions
+        run: |
+          HAS_AVX512F=$([[ $(lscpu | grep "avx512f" | wc -l) -eq 1 ]] && echo "_avx512f" || echo "")
+          HAS_AVX2=$([[ $(lscpu | grep "avx2" | wc -l) -eq 1 ]] && echo "_avx2" || echo "")
+          HAS_FMA=$([[ $(lscpu | grep "fma" | wc -l) -eq 1 ]] && echo "_fma" || echo "")
+          HAS_AVX=$([[ $(lscpu | grep "avx" | wc -l) -eq 1 ]] && echo "_avx" || echo "")
+          VECTOR_EXTENSIONS=${HAS_AVX512F}${HAS_AVX2}${HAS_FMA}${HAS_AVX}
+          echo "VECTOR_EXTENSIONS=$VECTOR_EXTENSIONS" >> $GITHUB_ENV
+      - name: Setup ccache
+        uses: hendrikmuhs/ccache-action@v1.2
+        with:
+          key: sanitize-${{ env.CXX }}-${{ matrix.sanitizer }}-${{ env.VECTOR_EXTENSIONS }}
       - name: Build arbor
         run: |
+          export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
           mkdir build
           cd build
           export SAN="-fsanitize=${{ matrix.sanitizer }} -fno-omit-frame-pointer"
-          cmake .. -DCMAKE_BUILD_TYPE=debug -DCMAKE_CXX_FLAGS="$SAN" -DCMAKE_C_FLAGS="$SAN" -DCMAKE_EXE_LINKER_FLAGS="$SAN" -DCMAKE_MODULE_LINKER_FLAGS="$SAN" -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_VECTORIZE=${{ matrix.simd }} -DARB_WITH_MPI=OFF -DARB_USE_BUNDLED_LIBS=ON -DARB_WITH_PYTHON=ON -DPython3_EXECUTABLE=`which python`
-          make -j4 VERBOSE=1 tests examples pyarb
+          cmake .. -GNinja -DCMAKE_BUILD_TYPE=debug -DCMAKE_CXX_FLAGS="$SAN" -DCMAKE_C_FLAGS="$SAN" -DCMAKE_EXE_LINKER_FLAGS="$SAN" -DCMAKE_MODULE_LINKER_FLAGS="$SAN" -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_VECTORIZE=${{ matrix.simd }} -DARB_WITH_MPI=OFF -DARB_USE_BUNDLED_LIBS=ON -DARB_WITH_PYTHON=ON -DPython3_EXECUTABLE=`which python`
+          ninja -j4 -v tests examples pyarb
           cd -
       - name: Run unit tests
         run: |
diff --git a/.github/workflows/test-everything.yml b/.github/workflows/test-everything.yml
index 27af676d65172532509db12c3ab4ac2448bfe7d5..c3c88375a9cb6a2a5ee11bf62f33e10a2de4e62a 100644
--- a/.github/workflows/test-everything.yml
+++ b/.github/workflows/test-everything.yml
@@ -97,11 +97,11 @@ jobs:
         if: ${{ startsWith(matrix.config.os, 'ubuntu') }}
         run: |
           sudo apt-get update
-          sudo apt-get install -y libxml2-dev libopenmpi-dev ${{ matrix.config.cc }}
+          sudo apt-get install -y libxml2-dev libopenmpi-dev ninja-build ccache ${{ matrix.config.cc }}
       - name: "MacOS: get build dependencies"
         if: ${{ startsWith(matrix.config.os, 'macos') }}
         run: |
-          brew install libxml2 openmpi
+          brew install libxml2 openmpi ninja ccache
       - name: Set up cmake
         uses: jwlawson/actions-setup-cmake@v1.13
         with:
@@ -118,6 +118,25 @@ jobs:
         uses: actions/checkout@v3
         with:
           submodules: recursive
+      # figure out vector extensions for ccache key
+      - if: ${{ contains(matrix.config.os, 'macos') }}
+        name: Check vector extensions
+        # assume uniform hardware for macos
+        run: |
+          echo "VECTOR_EXTENSIONS=" >> $GITHUB_ENV
+      - if: ${{ contains(matrix.config.os, 'ubuntu') }}
+        name: Check vector extensions
+        run: |
+          HAS_AVX512F=$([[ $(lscpu | grep "avx512f" | wc -l) -eq 1 ]] && echo "_avx512f" || echo "")
+          HAS_AVX2=$([[ $(lscpu | grep "avx2" | wc -l) -eq 1 ]] && echo "_avx2" || echo "")
+          HAS_FMA=$([[ $(lscpu | grep "fma" | wc -l) -eq 1 ]] && echo "_fma" || echo "")
+          HAS_AVX=$([[ $(lscpu | grep "avx" | wc -l) -eq 1 ]] && echo "_avx" || echo "")
+          VECTOR_EXTENSIONS=${HAS_AVX512F}${HAS_AVX2}${HAS_FMA}${HAS_AVX}
+          echo "VECTOR_EXTENSIONS=$VECTOR_EXTENSIONS" >> $GITHUB_ENV
+      - name: Setup ccache
+        uses: hendrikmuhs/ccache-action@v1.2
+        with:
+          key: ${{ matrix.config.os }}-${{ matrix.config.cxx }}-${{ matrix.variant }}-${{ env.VECTOR_EXTENSIONS }}
       - name: Check config
         run: |
           $CC --version
@@ -129,23 +148,25 @@ jobs:
       - if:   ${{ matrix.variant == 'static' }}
         name: Build arbor
         run: |
+          export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
           mkdir build
           cd build
-          cmake .. -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_PYTHON=ON -DARB_VECTORIZE=${{ matrix.config.simd }} -DPython3_EXECUTABLE=`which python` -DARB_WITH_MPI=${{ matrix.config.mpi }} -DARB_USE_BUNDLED_LIBS=ON -DARB_WITH_NEUROML=ON
-          make -j4 tests examples pyarb html
+          cmake .. -GNinja -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_PYTHON=ON -DARB_VECTORIZE=${{ matrix.config.simd }} -DPython3_EXECUTABLE=`which python` -DARB_WITH_MPI=${{ matrix.config.mpi }} -DARB_USE_BUNDLED_LIBS=ON -DARB_WITH_NEUROML=ON
+          ninja -j4 tests examples pyarb html
           cd -
       - if:   ${{ matrix.variant == 'shared' }}
         name: Build arbor
         run: |
+          export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
           mkdir build
           cd build
-          cmake .. -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_PYTHON=ON -DARB_VECTORIZE=${{ matrix.config.simd }} -DPython3_EXECUTABLE=`which python` -DARB_WITH_MPI=${{ matrix.config.mpi }} -DARB_USE_BUNDLED_LIBS=ON -DARB_WITH_NEUROML=ON -DBUILD_SHARED_LIBS=ON
-          make -j4 tests examples pyarb html
+          cmake .. -GNinja -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_PYTHON=ON -DARB_VECTORIZE=${{ matrix.config.simd }} -DPython3_EXECUTABLE=`which python` -DARB_WITH_MPI=${{ matrix.config.mpi }} -DARB_USE_BUNDLED_LIBS=ON -DARB_WITH_NEUROML=ON -DBUILD_SHARED_LIBS=ON
+          ninja -j4 tests examples pyarb html
           cd -
       - name: Install arbor
         run: |
           cd build
-          sudo make install
+          sudo ninja install
           cd -
       - name: Run unit tests
         run: |