The strength of GitHub Actions is the ecosystem around it. The Actions Marketplace contains tens of thousands of reusable building blocks — for everything from "checkout the repository" to "deploy to a Kubernetes cluster". This lesson teaches you how to consume them safely and how to build your own.
Anatomy of an Action Reference
- uses: actions/checkout@v4
- uses: docker/build-push-action@v6
- uses: hashicorp/setup-terraform@v3
- uses: ./.github/actions/my-local-action # local action in the repo
- uses: docker://alpine:3.20 # Docker image directly
The format is owner/repo@ref. The ref can be a branch, tag, or commit SHA.
The Three Action Types
| Type | Description | When to use |
|---|---|---|
| JavaScript | Node.js code that runs directly on the runner | Fast startup; runs on all runner OSes |
| Docker container | Runs a Docker image as the action body | Tool not available in JS; Linux runners only |
| Composite | A list of steps packaged as a single action | Reuse a sequence of shell + uses steps |
The Most-Used Official Actions
actions/checkout— fetch the repoactions/setup-node,setup-python,setup-go,setup-java,setup-dotnet— language runtimesactions/cache— restore/save build cachesactions/upload-artifact,download-artifact— pass files between jobsgithub/codeql-action— security scanningactions/github-script— call GitHub's API from a step
Pinning Actions for Security
An action you reference can be updated by its author at any time. If you reference by branch (@main), any push by the maintainer changes what runs in your pipeline — a supply-chain risk. Three pinning strategies:
| Strategy | Example | Trust level |
|---|---|---|
| Mutable branch | @main | Worst — never use |
| Major tag | @v4 | OK for verified creators — they re-tag carefully |
| Exact tag | @v4.1.7 | Better — auditable per release |
| Commit SHA | @a1b2c3d4... | Best — immutable |
GitHub's own guidance for production: pin third-party actions to a full SHA. Tools like Dependabot can keep these pinned-SHA references updated for you with proper PR review.
Reading an Action's action.yml
name: 'Setup Node.js'
description: 'Set up a specific version of Node.js'
inputs:
node-version:
description: 'Version spec'
required: false
default: 'lts/*'
outputs:
node-version:
description: 'Installed version'
runs:
using: 'node20'
main: 'dist/index.js'
Before using a third-party action, open its action.yml in the repo. Verify inputs, outputs, and — critically — that the main: file matches a committed file in the repo.
Building Your Own Composite Action
Composite actions are pure YAML and the easiest to author. Put one at .github/actions/setup-project/action.yml:
name: 'Setup project'
description: 'Checkout, install Node, restore npm cache, install deps'
runs:
using: 'composite'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- shell: bash
run: npm ci
Then reference it from a workflow:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: ./.github/actions/setup-project
- run: npm test
Composite actions accept inputs and produce outputs like any other action. They are perfect for the 4-6 step "setup my project" recipe that you'd otherwise copy-paste into every workflow.
Publishing an Action to the Marketplace
- Put your action at the root of a public repo (one action per repo)
- Add an
action.ymlwith name, description, branding - Tag a release (e.g., v1.0.0)
- From the release page, opt in to "Publish this Action to the Marketplace"
- Add a verified creator badge by joining the GitHub Verified Creators program (if eligible)
Marketplace Trust Signals
- GitHub Verified badge — vetted creators (GitHub, AWS, Microsoft, HashiCorp, etc.)
- Star count and download count
- Repo activity (recent commits, issue response)
- Last release date — abandoned actions are a risk
- Number of contributors
- Whether the action source has minified
dist/(harder to audit) vs unminified
When to Build vs Buy
Most teams use Marketplace actions for generic concerns (setup, checkout, cloud auth, container builds) and write composite or local actions for domain-specific work (their bespoke deployment, their internal test runner). The breakpoint is: if the action's logic is fewer than 30 lines of shell and you'll only use it inside your own org, write it as a composite action inside the repo.