GitHub Actions pip Cache Not Working for Python Projects
In GitHub Actions workflows for Python projects, pip install times are slow and it appears that the pip cache is not being used between workflow runs. Even when using the actions/cache
step, dependencies are reinstalled from scratch. How can pip caching be enabled and made effective in GitHub Actions?
Solution
To enable pip cache in GitHub Actions, you need to cache the pip cache directory. For most systems, this is ~/.cache/pip
. Here is an example of how to do this:
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: pip install -r requirements.txt
Make sure the cache key includes a hash of your requirements file. This will ensure the cache is updated when dependencies change. If you use pip install --no-cache-dir
, remove that flag to allow caching.
Alternative #1
I've found that sometimes the cache key strategy needs to be more granular. If you have multiple Python versions or different dependency files, you should include them in the cache key:
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ runner.python-version }}-${{ hashFiles('**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-${{ runner.python-version }}-
${{ runner.os }}-pip-
This ensures separate caches for different Python versions and dependency files, which can significantly improve cache hit rates.
Alternative #2
If you're using Poetry instead of pip, the cache location is different. You need to cache the Poetry cache directory:
- name: Cache Poetry
uses: actions/cache@v4
with:
path: ~/.cache/pypoetry
key: ${{ runner.os }}-poetry-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-poetry-
- name: Install dependencies
run: poetry install
This is especially useful if you're migrating from pip to Poetry or using both in different projects.
Alternative #3
For monorepos or projects with multiple dependency files, you might want to cache each directory separately:
- name: Cache pip for backend
uses: actions/cache@v4
with:
path: backend/.cache/pip
key: ${{ runner.os }}-pip-backend-${{ hashFiles('backend/requirements.txt') }}
- name: Cache pip for frontend
uses: actions/cache@v4
with:
path: frontend/.cache/pip
key: ${{ runner.os }}-pip-frontend-${{ hashFiles('frontend/requirements.txt') }}
This approach gives you more granular control over caching and can be more efficient for large projects with many dependencies.