The cache action should be placed before any step that consumes or creates that cache. This step is responsible for:
- defining cache parameters.
- restoring the cache, if it was cached in the past.
GitHub Actions will then run a "Post *" step after all the steps, which will store the cache for future calls.
See the example workflow from the documentation.
For example, consider this sample workflow:
name: Caching Test on: push jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Enable Cache id: cache-action uses: actions/cache@v2 with: path: cache-folder key: ${{ runner.os }}-cache-key - name: Use or generate the cache if: steps.cache-action.outputs.cache-hit != 'true' run: mkdir cache-folder && touch cache-folder/hello - name: Verify we have our cached file run: ls cache-folder
This is how it looks on the first run: 
And this is how it looks on the second run: 
GitHub will not invalidate the cache. Instead, it is the responsibility of the developer to ensure that the cache key is unique to the content it represents.
On common way to do this, is to set the cache key so that it contains a hash of a file that lives in the repository, so that changes to this file, will yield a different cache key. A good example for such a behavior, is when you have lock files that list all your repository's dependencies (requirements.txt for pyrhon, Gemfile.lock for ruby, etc).
This is achieved by a syntax similar to this:
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
as described in the Creating a cache key section of the documentation.
haskell/actions/setupwhich is installing tools, caching goes after?