# action-download-artifact finds the run first and downloads the artifact second

> dawidd6/action-download-artifact extends the official GitHub artifact download action by searching for a workflow run using workflow, commit, branch, tag, pull request, event or run criteria before pulling its artifacts, which is what cross repository and cross workflow pipelines actually need.

**dawidd6/action-download-artifact** — :gear: GitHub Action for downloading artifacts associated with given criteria

- Repository: https://github.com/dawidd6/action-download-artifact
- Stars: 831 · Forks: 238
- Language: JavaScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/dawidd6-action-download-artifact

## The gap the official action leaves open

The problem this action solves is stated in its first paragraph and it is narrower than it sounds. The official actions/download-artifact can download from another workflow run when its exact run ID is known. That is a real constraint in practice, because the run ID is exactly the thing a pipeline usually does not know.

Consider the common cases. A workflow that wants the artifacts produced by the pull request that triggered it does not have a run ID, it has a pull request number and a head commit SHA. A release workflow that wants the artifacts of the commit it is tagging knows a ref but not a run. A deploy job that consumes build output from another repository knows a branch and a workflow file. In all of those situations the caller must first resolve run to ID, and that resolution is the awkward part, because the GitHub API returns runs and you have to filter them.

dawidd6/action-download-artifact does that resolution inside the action. It finds a run by workflow, commit, branch, tag, pull request or other criteria and then downloads its artifacts. The implementation is JavaScript in main.js with an action.yml entry point, and the dependencies show the shape of the job: @actions/artifact for the artifact service, @actions/core for inputs and outputs, @actions/github for the API calls, and adm-zip for extraction.

For a team whose build and deploy are separate workflows, that is the whole value proposition. The action replaces a chunk of API filtering glue with a set of declared inputs.

## Pick one criterion or none, because the inputs override each other

The README is unusually firm about how the inputs combine. If commit, pr, branch, ref, run_id or workflow_conclusion is not specified, the artifact from the most recent successfully completed workflow run will be downloaded. And the instruction is explicit: do not specify pr, commit, branch, ref or run_id together, or workflow_conclusion and run_id together. Pick just one of each or none.

That constraint is the design in miniature. Every criterion is a filter, and stacking filters would either conflict or make the outcome impossible to reason about. If you set both branch and ref, which one wins? The README answers that in the input comments: ref is a branch, tag or commit ID to reference and it can supersede both branch and commit. But rather than leaving ambiguity, the action asks you to choose one.

The criteria available are richer than the official action. There is workflow for the workflow file name or ID, which is inferred from run_id if that is set or defaults to the current workflow. There is workflow_conclusion, which accepts a conclusion such as failure, success, neutral, cancelled, skipped, timed_out or action_required, or a status such as completed, in_progress or queued, and the empty string means ignore status and conclusion in the search. There is event for the trigger type, run_number for a run number within a workflow, and run_id for an exact run.

There is also workflow_search, which is false by default. When no workflow is set and workflow_search is true, the most recent workflow matching all the other criteria is looked up instead of the current workflow, which is how you search across workflow files in a repository.

## Some filters run in the API, the rest are evaluated inside the action

The API usage section explains which part of the search costs what, and it is the section to read before pointing this at a repository with a long run history.

Workflow, branch, event and commit or ref filters are sent to GitHub's API as part of the run query. The remaining inputs are evaluated by the action itself: workflow_conclusion, run_number, fork filtering, check_artifacts and search_artifacts.

That distinction has a cost attached to it. Artifact checks may require an additional paginated API request for every candidate workflow run, so a search that filters on the server and then checks artifacts locally can multiply the number of API calls. That matters for rate limits and for the wall clock time of a job.

Two inputs exist precisely to narrow this. check_artifacts asks the action to check whether a workflow run has an artifact at all, and if not, take the last available artifact from a previous workflow run. search_artifacts searches for the last workflow run that stored an artifact named as in the name input. Both default to false, and the default behavior is simply to try to download from the most recent matching run.

Two further behaviors are worth planning for. Expired artifacts do not satisfy check_artifacts or search_artifacts, so runs whose artifacts are gone are skipped rather than causing a download failure. And candidate runs are sorted newest first by the action itself, rather than relying on the order the API returns them in, which removes one source of nondeterminism in which run gets picked.

## Naming artifacts with a regular expression and unpacking them

Once the run is found, the artifact selection inputs decide what lands on disk.

The name input selects the uploaded artifact by name. If it is not specified, all artifacts are downloaded and extracted into their respective subdirectories, following the same convention as the official action. If name_is_regexp is set to true, the name is treated as a regular expression instead of a literal, and only the artifacts whose names match are downloaded. merge_multiple then controls the layout: when several artifacts match a regular expression, they can be merged into a single directory instead of separate ones.

Extraction has two paths. By default the action unpacks the artifact itself using adm-zip. Setting use_unzip to true switches to the unzip system utility instead, and the README gives the reason for the alternative: on GitHub Enterprise Server, use_unzip: true is recommended for large artifacts so extraction does not load the complete ZIP into memory. That is a memory behavior difference, not a speed claim, and it only matters on self hosted runners where the archive is big.

Two more inputs shape what happens when nothing is found. skip_unpack lets you keep the downloaded archive without extracting it. if_no_artifact_found decides how the step exits when there is no artifact, with the options fail, warn and ignore, and fail is the default. allow_forks, whose documented default is false, controls whether forks are included when searching for artifacts.

## Tokens decide whether the search can see anything at all

The github_token input is where most misconfigurations start. The comment in the README describes three cases. The GitHub token is optional, but a Personal Access Token with public_repo scope is needed if the artifact is from a different repository. If the repository is private, a Personal Access Token with repo scope is needed, or the GitHub token can be used in a job where the action permission scope is set to read.

That is the difference between the two token models, and it decides how flexible your search can be. The GitHub token issued to a job is scoped to that repository, so it can find runs in the current repository but not across repositories. A Personal Access Token is what lets the same workflow reach another repository, which is the scenario where run by commit or branch is most useful.

The repo input, which defaults to the current repository, is the companion to that. Set repo to another repository and you need a token that can see it.

The permission model also has a subtlety in the wording: for a private repository, the GitHub token works in a job where the action scope is set to read. Read access to artifacts is enough for downloading, so the requirement is narrower than write access, but it still has to be granted in the workflow permissions rather than assumed.

Because the search is broad and the token is narrow, the combination is where the failures live. A search that returns nothing is far more often a permission problem than an absence of artifacts, and the if_no_artifact_found setting decides whether you find out as a red build or a warning.

## A short workflow example and how to pin it

Using the action means adding a step to a workflow with the inputs you need. The README's own example covers the common shape:

```yaml
- name: Download artifact
  id: download-artifact
  uses: dawidd6/action-download-artifact@<REF>
  with:
    github_token: ${{secrets.GITHUB_TOKEN}}
    workflow: workflow_name.yml
    workflow_conclusion: success
    name: artifact_name
    name_is_regexp: true
    path: extract_here
    repo: ${{ github.repository }}
    if_no_artifact_found: fail
```

The step carries an id, download-artifact, so its outputs are available to later steps in the same job. The path input chooses the extraction directory and defaults to the current directory, and repo targets the repository the artifacts come from, defaulting to the current one.

The uses line ends in <REF> rather than a version, which is a placeholder for a tag or commit SHA of this action. That is the detail to get right. The project ships its own release tags, and the recent ones are v27 from 2026-09-29, v26 from 2026-09-28 and v25 from 2026-09-25, so pinning to a major tag such as v27 gives you a moving minor release, while a commit SHA gives you a fixed one. The action runs on the runner as JavaScript, so no toolchain setup is needed on the runner itself.

## Self hosted runners and glibc are the upgrade cost to plan for

There is one maintenance constraint that the README puts in the troubleshooting section, and it is the kind that breaks a pipeline in the middle of a release.

The v3 release of this action switched from node16 to node20 as the runtime. Node 20 requires glibc 2.28 or newer. If a self hosted runner has an older glibc, the documented workaround is to pin to the v2 release, with the explicit warning that v2 will not receive any updates.

That is the whole upgrade cost story: a runner fleet on an old distribution either upgrades the base image or freezes on a release line that no longer gets fixes. The other operational point for self hosted runners is the use_unzip option, which avoids loading a whole ZIP into memory during extraction.

The project is MIT licensed, with the license in the LICENSE file at the repository root, and it is not archived. The last push was on 2026-10-06, and the release tags show a steady cadence through September 2026 with v27, v26 and v25 published within the same week. The repository also carries a renovate.json for dependency updates and a committed node_modules directory with a package-lock.json, which means the action runs from vendored dependencies rather than resolving them on the runner.

## Conclusion

This action is the right choice when a pipeline must consume artifacts from a run it cannot name by ID, for example a pull request build, a tag, a branch or another repository, and it is the wrong choice when you already know the exact run ID, where the official actions/download-artifact is simpler; before adopting it, confirm your runner meets the glibc 2.28 requirement of the v3 and later releases, and decide in advance how the job should behave when nothing matches, since if_no_artifact_found defaults to fail.

## FAQ

### How do I download a GitHub Actions artifact from another workflow run?

Use dawidd6/action-download-artifact and set the criteria, for example workflow together with commit or branch or pr. The action finds the matching run and downloads its artifacts, while the official actions/download-artifact needs the exact run ID.

### Which inputs can I combine in action-download-artifact?

The README says not to specify pr, commit, branch, ref or run_id together, and not to combine workflow_conclusion with run_id. Pick just one of each or none, and if none is given the most recent successfully completed workflow run is used.

### Why does my download step find no artifact?

The most common cause is the token rather than a missing artifact. The GitHub token only sees the current repository, so a Personal Access Token with public_repo scope is needed for another repository and repo scope is needed for a private one, and expired artifacts do not satisfy check_artifacts or search_artifacts so those runs are skipped.

### What happens if the action-download-artifact action cannot find an artifact?

The if_no_artifact_found input decides how the step exits. It accepts fail, warn or ignore, and the default is fail, so a job with no matching artifact fails unless you change that setting.

### Does action-download-artifact work on GitHub Enterprise Server runners?

The README notes that v3 switched the runtime from node16 to node20, which requires glibc 2.28 or newer, so older self hosted runners should pin to the v2 release which will not receive updates. For large artifacts it also recommends use_unzip: true so extraction does not load the complete ZIP into memory.

## Sources

- [dawidd6/action-download-artifact on GitHub](https://github.com/dawidd6/action-download-artifact)
- [Issues](https://github.com/dawidd6/action-download-artifact/issues)
- [License: MIT](https://github.com/dawidd6/action-download-artifact/blob/master/LICENSE)
- [README](https://github.com/dawidd6/action-download-artifact/blob/master/README.md)
- [Releases](https://github.com/dawidd6/action-download-artifact/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dawidd6-action-download-artifact
