Comparison of GitHub Actions with competitors
Deep dive into workflow syntax, triggers, and job configuration
Explore matrices, reusable workflows, and composite actions
•Runner Types and Execution Environments
•Persisting Build Outputs with Artifacts
•Controlling GitHub Permissions
•Authenticating to Third-Party Systems
•Matrix Strategies, Conditionals, and Concurrency Controls
Discover and integrate community actions from the GitHub Marketplace
Build custom JavaScript and Docker actions from scratch
•JavaScript and TypeScript Actions
Optimize logs, secrets, environments, and permissions for teams
•Developer Experience (Actions)
Harden workflows with security, reliability, and cost-saving techniques
•Maintainable Workflow Patterns
Apply course concepts by automating a real-world deployment pipeline
Whereas artifacts are meant for long-lived outputs, caches store intermediary data (dependencies, build toolchains, etc.) to speed up subsequent runs. GitHub's hosted cache stores up to 10 GB of data per repository and evicts older entries as new ones are added.
The generic actions/cache
action lets you save arbitrary directories keyed by a hash you control:
jobs:
actions-cache:
name: Prime demo cache
runs-on: ubuntu-24.04
steps:
# Attempt to restore (misses on first run)
- name: Restore cache
id: demo-cache
uses: actions/cache@638ed79f9dc94c1de1baef91bcab5edaa19451f4 # v4.2.4
with:
path: demo-cache
# For info on constructing an appropriate cache key see:
# https://github.com/actions/cache?tab=readme-ov-file#creating-a-cache-key
key: demo-cache-v1
# Populate directory only on miss
- name: Populate cache directory
if: steps.demo-cache.outputs.cache-hit != 'true'
run: |
echo "Cache miss – generating contents"
mkdir -p demo-cache
date > demo-cache/timestamp.txt
# Save cache only if we generated new content
- name: Save cache
if: steps.demo-cache.outputs.cache-hit != 'true'
uses: actions/cache@638ed79f9dc94c1de1baef91bcab5edaa19451f4 # v4.2.4
with:
path: demo-cache
key: demo-cache-v1
- name: Verify cache status
run: |
echo "cache-hit? -> ${{ steps.demo-cache.outputs.cache-hit }}"
cat demo-cache/timestamp.txt
Many setup actions include purpose-built caching. For example, actions/setup-node
can automatically cache node_modules
based on a lockfile so future installs simply hydrate from the cache:
jobs:
node-cache:
name: npm dependency cache (setup-node)
runs-on: ubuntu-24.04
defaults:
run:
working-directory: 04-advanced-features/caching/minimal-node-project
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
- uses: actions/setup-node@d7a11313b581b306c961b506cfc8971208bb03f6 # v4.4.0
with:
node-version: 20
cache: npm
# Point cache action at the specific lock-file path
cache-dependency-path: 04-advanced-features/caching/minimal-node-project/package-lock.json
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
- name: List first few modules
run: ls -R node_modules | head
Third-party runner providers sometimes offer alternative caching models. Namespace's cache volumes snapshot an entire directory and mount it back in on later runs, which avoids large upload/download cycles and can dramatically shrink build durations, especially for dependency-heavy projects or language toolchains.
See this benchmarking workflow for a comparison between the standard GitHub Actions Cache and Namespace cache volumes!