10.3 Artifacts Management & Job Handoff
Key Takeaways
- GitHub Actions artifacts provide persistent, immutable storage for build outputs, compiled binaries, test reports, and diagnostic logs intended for cross-job handoff or post-run human inspection.
- Modern artifact management utilizes `actions/upload-artifact@v4` and `actions/download-artifact@v4`, featuring upgraded chunked transfer performance, automatic compression, and immutable artifact naming.
- Retention defaults to 90 days and is configurable from 1 to 90 days in public repositories and 1 to 400 days in private and internal repositories; short `retention-days` values on transient cross-job artifacts prevent storage-quota overage.
- Artifacts and Caching serve fundamentally distinct architectural purposes: Caching stores mutable, recreatable dependencies to speed up future runs; Artifacts store immutable, final build deliverables and reports to share across jobs or retain after workflow completion.
- In multi-job pipelines, `download-artifact@v4` allows selective downloading by artifact `name` into specific target directories or downloading all workflow artifacts simultaneously using `pattern:` or omitting `name`.
Artifacts Management & Job Handoff
In continuous integration and delivery pipelines, workflows are frequently structured as multi-job Directed Acyclic Graphs (DAGs). For example, a build job compiles source code into platform binaries, a parallel test matrix runs integration suites against those binaries, and a final deploy job packages and ships the release to production.
Because every job in GitHub Actions executes on an isolated, ephemeral virtual machine or container runner, files created in one job do not persist on disk for subsequent jobs. To transfer data across jobs and preserve build deliverables (such as compiled binaries, test coverage reports, SARIF scan files, and deployment packages) for post-execution download, GitHub Actions provides the Artifacts subsystem.
1. Modern Artifact Architecture: v4 Enhancements
Artifact management in GitHub Actions is powered by two official actions: actions/upload-artifact@v4 and actions/download-artifact@v4.
+-----------------------------------------------------------------------------+
| MULTI-JOB ARTIFACT PIPELINE FLOW |
| |
| +---------------------------------------------------------------------+ |
| | JOB 1: 'build-application' (Runner VM A) | |
| | 1. Compile source code -> generates './dist/app-v1.0.tar.gz' | |
| | 2. actions/upload-artifact@v4 (name: 'release-tarball', path: dist) | |
| +---------------------------------------------------------------------+ |
| | |
| Uploaded to GitHub Blob Storage (Immutable Zip) |
| | |
| +--------------------+--------------------+ |
| | | |
| v v |
| +---------------------------+ +---------------------------+ |
| | JOB 2: 'test-e2e' (VM B) | | JOB 3: 'deploy-prod' (VM C| |
| | needs: build-application | | needs: [build, test-e2e] | |
| | download-artifact@v4 | | download-artifact@v4 | |
| | (name: 'release-tarball') | | (name: 'release-tarball') | |
| | Executes automated tests | | Deploys binary to cloud | |
| +---------------------------+ +---------------------------+ |
+-----------------------------------------------------------------------------+
Key Architectural Enhancements in upload-artifact@v4
- Up to 10x Performance Improvement: Artifacts v4 uses a completely redesigned chunked, parallel upload engine backed by direct Azure blob storage, drastically reducing upload/download latency for large archives.
- Artifact Immutability: Once an artifact with a specific name (e.g.,
build-output) is uploaded in a workflow run, it cannot be modified or appended to by subsequent steps in the same run unless uploaded with a unique name or merged. - Scoped ID Identifiers: Every uploaded artifact receives a unique GitHub artifact ID, exposed via the action's output (
${{ steps.upload.outputs.artifact-id }}).
2. Configuration & Parameter Deep Dive
actions/upload-artifact@v4 Parameters
- name: Upload Production Build Artifact
id: upload-build
uses: actions/upload-artifact@v4
with:
# Name of the artifact archive (Default: 'artifact')
name: production-binaries
# File, directory, or wildcard glob pattern to upload
path: |
bin/
dist/*.tar.gz
!dist/*.tmp
# Retention period in days, bounded by the repository setting
retention-days: 5
# Behavior if no matching files are found: 'error', 'warn', or 'ignore'
if-no-files-found: error
# Zip compression level: 0 (store), 1 (fast), up to 9 (maximum compression)
compression-level: 6
# Overwrite an existing artifact with the same name (Default: false)
overwrite: false
actions/download-artifact@v4 Parameters
- name: Download Specific Artifact
uses: actions/download-artifact@v4
with:
# Name of the specific artifact to download
name: production-binaries
# Destination directory to extract artifact contents (Default: current directory)
path: ./downloaded-binaries
Downloading Multiple or All Artifacts
If a workflow generates multiple artifacts (e.g., coverage-frontend, coverage-backend, coverage-e2e), downstream jobs can download all of them simultaneously by omitting the name: input or using a pattern::
- name: Download All Test Coverage Artifacts
uses: actions/download-artifact@v4
with:
pattern: coverage-*
path: ./all-coverage-reports
merge-multiple: true # Extracts all matching artifacts into the same directory
3. Retention Policies, Storage Quotas & Billing Management
Artifact storage is not free for private repositories once included GitHub plan storage allowances are exceeded.
Retention Configuration Levels
- Repository / Organization Defaults: Administrators configure the retention limit under
Settings > Actions > General > Artifact and log retention. The default is 90 days. The configurable range depends on repository visibility: 1 to 90 days for public repositories and 1 to 400 days for private and internal repositories. A managed repository can never exceed the ceiling set by its organization or enterprise. - Workflow-Level Override: Individual steps set
retention-days:to shorten (or, in a private repository whose settings allow it, lengthen) retention for that artifact. The value can never exceed the repository or organization maximum - a workflow can only tighten what the administrator permits.
Best Practice for Cost Optimization
- Transient Cross-Job Artifacts (1–3 Days): For artifacts used solely to pass compiled code between jobs (e.g., passing a binary from
buildtotest), setretention-days: 1orretention-days: 3. This ensures the artifact is automatically purged quickly, preventing repository storage bloat. - Release Assets & Audit Reports (30–90 Days): For regulatory audit logs, SARIF scan records, or release deliverables, use longer retention or publish them directly to GitHub Releases or GitHub Packages.
Programmatic Artifact Deletion
Artifacts can be downloaded and deleted programmatically before their expiration date using the REST API or GitHub CLI:
# List artifacts for a repository
gh api /repos/{owner}/{repo}/actions/artifacts
# Delete an artifact programmatically
gh api --method DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}
4. Comprehensive Comparison: Artifacts vs. Caching
A critical distinction on the GH-200 examination is knowing when to architect a pipeline using Artifacts versus Caching.
| Technical Dimension | GitHub Actions Artifacts (actions/upload-artifact) | GitHub Actions Cache (actions/cache) |
|---|---|---|
| 1. Primary Purpose | Passing build outputs between jobs within a run; preserving final deliverables for humans/deployment. | Reusing package dependencies and build trees across runs to speed up workflow execution. |
| 2. Data Mutability | Immutable: Artifacts represent a fixed point-in-time snapshot associated with a specific workflow run. | Mutable / Key-Invalidated: Overwritten or newly created when lockfile dependencies change. |
| 3. Scope & Persistence | Scoped strictly to an individual workflow run ID. Retained 1-90 days (public) or 1-400 days (private/internal), default 90. | Scoped to the repository and branch hierarchy. Shared across multiple workflow runs. |
| 4. Cross-Job Sharing | Designed specifically for sharing files across separate jobs in the same workflow run. | Can be shared across jobs, but requires cache key lookup and network restore overhead. |
| 5. Storage Limits | Consumes the account-wide GitHub Actions storage quota; included storage varies by plan (500 MB on Free up to 50 GB on Enterprise Cloud) and overage is billed. | Hard limit of 10 GB total per repository, not billed against account storage. |
| 6. Eviction Mechanism | Explicit time-based expiration via retention-days, bounded by the repository setting. | LRU (Least Recently Used) eviction when > 10 GB, or automatically after 7 days of inactivity. |
| 7. Web UI Availability | Downloadable as a Zip archive directly from the GitHub Actions run summary page. | Not directly downloadable by humans in the UI; accessible only by runners during workflow execution. |
| 8. Typical Content | Binaries, deployment packages, test HTML reports, code coverage XML, SARIF scan files. | ~/.npm, ~/.cache/pip, ~/.m2/repository, node_modules, compiled object files (.o, .class). |
A CI/CD workflow contains two jobs: build (which compiles a production Go binary) and deploy (which uploads the binary to Kubernetes). Each job executes on a separate virtual runner. What is the standard, secure mechanism to transfer the compiled binary from build to deploy?
An enterprise DevOps team discovers their organization is incurring extra storage costs due to gigabytes of transient test logs uploaded during pull request runs. How should the team configure actions/upload-artifact@v4 in their CI workflow to eliminate unnecessary storage consumption?
When architecting a high-performance CI/CD pipeline, how should an engineer differentiate between the use cases of actions/cache versus actions/upload-artifact?