GitHub reports that roughly four million artifacts are created every day, so a small change to one artifact-download step can affect far more than a CI convenience feature. Moving from actions/download-artifact@v3 to a mutable @v4 tag may improve workflow behavior, but it also gives someone else control over what code your runner executes later.
The safer change is not “replace v3 with v4.” It is a three-part review: choose a specific v4 release, resolve that release to its full commit identifier, then prove that your workflow still uses the v4 inputs and downloaded directory layout you expect. Treat the action reference as production dependency data, not as decoration in YAML.
1. Start with an inventory, not a search-and-replace
Find every workflow that invokes the action before changing anything. Repositories commonly download artifacts in release jobs, integration-test jobs, reusable workflows, and deployment workflows that only run on tags. Updating one visible build workflow while leaving a nightly deployment workflow on an older action creates two artifact behaviors to maintain.
git grep -n "actions/download-artifact@" -- .github/workflows
git grep -n "download-artifact" -- .github/workflows
For each match, record the current reference and the inputs beside it. The inputs matter more than the action line alone: name, path, pattern, merge-multiple, artifact-ids, repository, run-id, and github-token describe different download modes.
| Workflow pattern | What to inspect before upgrading | Most useful validation |
|---|---|---|
| One artifact from the same run | name and path |
Confirm the expected file exists at the expected path. |
| All artifacts | Whether later commands assume artifact-name subdirectories | Print the downloaded tree before packaging or deploying. |
| Several matching artifacts | pattern and merge-multiple |
Check file collisions and final directory structure. |
| Another workflow run or repository | repository, run-id, and token access |
Run the consuming workflow against a known producer run. |
This inventory also gives reviewers a bounded change set. A pull request changing three pinned action lines and three documented input checks is much easier to assess than a repository-wide “artifact modernization” patch.
2. Know what the pin actually protects
A major tag such as @v4 is convenient but mutable: maintainers can move it to a newer v4 release. That is useful when you intentionally want automatic updates, but it defeats an approval process that audited one revision and expects the runner to execute that exact revision next week.
A full commit reference instead identifies a specific Git commit. GitHub Actions accepts this form:
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
The 40-character value above is a commit identifier associated with a v4 release of actions/download-artifact. In a real repository, keep the human-readable release label in a comment so that a reviewer does not need to recognize a long hexadecimal string from memory.
- name: Download build output
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: web-dist
path: dist
Do not confuse the terminology here. Some supply-chain guidance loosely calls this “SHA-256 pinning,” while GitHub Action examples normally use a full Git commit SHA in uses:. The operational rule is simpler: use the complete commit value shown by the reviewed action release, not a mutable branch or major-version tag.
3. Select the intended v4 release before copying its SHA
“Latest v4” is not a sufficiently reviewable decision. It changes over time, and it does not tell a future maintainer which release notes, examples, or source revision your team evaluated. Instead, make an explicit selection from the actions/download-artifact releases page.
- Open the release page for the official
actions/download-artifactrepository. - Select the v4 release your repository intends to adopt.
- Read that release’s notes and the repository README’s v4 usage, inputs, outputs, and examples.
- Open the release tag or commit and copy the complete commit SHA.
- Put that exact SHA in
uses:, followed by a comment naming the selected v4 release.
The important separation is between discovery and execution. You may use the readable release label to discover what changed, but the workflow executes the reviewed commit. That preserves a stable build input even if the readable tag is moved later.
GitHub’s v4 announcement describes up to 10x performance improvements and warns of key differences that can require workflow updates. That combination is why blindly changing only the reference is risky: faster artifact handling does not guarantee your consuming job sees files in the same place or under the same selection rules.
4. Make the smallest possible v4 patch
Keep the first upgrade intentionally narrow. Do not rename artifacts, reorganize deployment directories, and revise permissions in the same pull request unless one of those changes is required to restore behavior. A tight diff makes it possible to answer one useful question: did changing the action implementation alter this workflow?
For a same-run, single-artifact consumer, the desired patch is usually only the reference:
- name: Download build artifact
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: application-linux
path: release-input
Preserve the existing explicit path. Relying on a default download location makes later commands fragile because commands such as tar, rsync, and release upload scripts often assume a particular working directory. An explicit path: release-input gives the post-download command a stable contract.
If the current workflow has no explicit path, add an inspection step during the upgrade rather than guessing what a downstream command receives. Remove the inspection after the behavior is verified, or retain a concise check if the deployment is high risk.
5. Validate the documented download mode, not just a green job
A green workflow can still deploy the wrong directory, upload an empty archive, or combine files from two matrix jobs. Validation should correspond to the documented mode used by your workflow. The official action documentation includes examples for downloading a single artifact, all artifacts, artifact IDs, multiple filtered artifacts, another workflow run or repository, and preserving file permissions.
For a single named artifact, validate its path and contents immediately after the action:
- name: Inspect downloaded files
shell: bash
run: |
test -d release-input
find release-input -maxdepth 3 -type f -print
test -f release-input/app.tar.gz
For all-artifact downloads, do not merely test that the action succeeded. Print the directory tree and compare it with the path consumed by the next step. For filtered downloads, verify that the filter selected the expected number of artifact directories. For merged downloads, inspect duplicate filenames because merging is exactly where two producers can overwrite one another in a shared destination.
A useful rule is: validate the file that the next command actually consumes. Testing that release-input exists is weaker than testing release-input/app.tar.gz when the deployment command uploads that archive.
6. Treat cross-run downloads as an authorization test
Downloading from another workflow run or repository has more moving parts than downloading from the current run. The documented inputs for that mode include repository, run-id, and github-token. A v4 SHA pin protects the action code you invoke; it does not prove that the token can read the intended artifact or that the selected run produced the intended build.
- name: Download approved package
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: release-package
repository: octo-org/product
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.ARTIFACT_READ_TOKEN }}
path: incoming
Before merging this pattern, test with a known producer run and verify the artifact name in that run’s UI. Then check the token’s access using the least privilege your repository policy allows. The common failure is diagnosing an authorization or run-selection problem as an action-version problem because both surface at the download step.
Also review trust boundaries. If a deployment workflow downloads output produced by another workflow, the producer run is part of the deployment’s input chain. The SHA pin prevents unexpected action code changes; it does not make unreviewed producer output trustworthy.
7. Check file permissions where artifacts become executable
Artifact downloads are often harmless test reports, but release pipelines frequently download shell scripts, binaries, installers, or deployment bundles. The repository documentation includes a file-permissions example, which is a signal to test permissions rather than assuming an executable bit survived your specific upload-and-download path.
Add a focused check when the next step invokes a downloaded file:
- name: Verify release script
shell: bash
run: |
test -f incoming/deploy.sh
test -x incoming/deploy.sh
./incoming/deploy.sh --check
If that test fails, fix the workflow deliberately. Your options may include restoring permissions in a controlled step or packaging the deliverable in a format that carries the metadata your release process requires. Do not hide the problem with a broad chmod -R on every downloaded file: that makes executable data out of files that were never intended to run.
This is one of the second-order costs of artifact upgrades. The action reference change is one line; the operational contract includes filenames, directory shape, access rights, and executable permissions. A 10-minute validation run is cheaper than a release job that discovers a permission issue after an approval window opens.
8. Make future SHA updates routine rather than exceptional
A SHA pin trades automatic action movement for an explicit maintenance task. That is the point, but it can become team friction if every update requires rediscovering the same review process. Store enough context beside the pin for another engineer to repeat the decision without guessing.
- name: Download test reports
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0, reviewed 2026-08
with:
name: junit-results
path: test-results
Use an update pull request that contains four things: the old SHA, the new SHA, the selected release label, and evidence from a workflow run. If your repository uses an automated dependency-update tool, configure it to propose action updates as pull requests rather than granting a mutable tag control of production workflows.
| Reference style | Update behavior | Review consequence |
|---|---|---|
@v4 |
Can change without a workflow-file commit. | The executed revision may differ from the reviewed revision. |
@v4.3.0 |
Readable, but still depends on tag handling. | Better release intent, not the strongest immutable review record. |
| Full commit SHA | Changes only when the workflow reference changes. | Each action revision is visible in repository history. |
9. Run this upgrade checklist this week
Pick one non-production workflow first, preferably one that downloads a single artifact and has an easy-to-read output such as a test report or packaged archive. Complete the procedure once, then apply the same review shape to the rest of the repository.
- Run
git grepto find everyactions/download-artifactuse. - Choose one explicit v4 release from the official repository’s release page.
- Copy the full commit SHA associated with that reviewed release.
- Replace only the action reference and add a release-label comment.
- Compare every existing
with:input with the action’s documented inputs and examples. - Add a temporary file-tree or exact-file assertion after the download.
- Trigger the workflow using a known artifact-producing run.
- Review the artifact path, selected files, token behavior, and permissions where applicable.
- Merge the SHA update with the workflow-run link in the pull request, then repeat for the next workflow.
That procedure gives you both sides of the v4 upgrade: the performance and feature improvements GitHub describes, plus an immutable action dependency that cannot silently change under a familiar major-version tag. The durable result is not one pinned line of YAML; it is a reviewable method your repository can use for every future action update.