Artifact Management: Persisting Build Outputs in GitHub Actions
Master artifact management to save build outputs and test reports in GitHub Actions. Learn how to upload and download files for inspection after your CI runs.

Previously in this course, we explored advanced pipeline caching to speed up our builds by reusing dependencies. Today, we shift our focus from performance to persistence: how do we save the actual results—our binaries, logs, or test reports—so they don't vanish the moment our CI job finishes?
Understanding Artifacts and Storage
In GitHub Actions, each job runs in a fresh, ephemeral virtual machine. When the job finishes, the runner is destroyed, and the file system is wiped clean. If you generate a compiled binary, a PDF report, or a set of logs during your build, you lose them instantly.
Artifacts are the mechanism GitHub provides to "extract" files from that temporary environment and store them in the cloud, attached to your specific workflow run. Think of them as a temporary storage bridge for your build outputs that allows you to inspect, debug, or deploy your code later.
Uploading Build Artifacts
To persist files, we use the official actions/upload-artifact action. This action looks at a path in your runner's workspace, zips the contents, and uploads them to the GitHub storage service.
Here is a concrete example. Suppose your application generates a dist/ folder containing your compiled code and a test-results/ folder containing an HTML coverage report.
YAMLjobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build and Test run: | mkdir -p dist test-results echo "Binary content" > dist/app.bin echo "Test report content" > test-results/report.html - name: Upload Build Artifacts uses: actions/upload-artifact@v4 with: name: build-outputs path: | dist/ test-results/ retention-days: 5
Key configuration points:
- name: The identifier for your artifact in the UI.
- path: Supports wildcards or multiple paths (as shown above).
- retention-days: Defaults to 90 days, but you can lower this to save space if you only need the data for immediate debugging.
Downloading Artifacts
Once uploaded, you can access these files in two ways:
- Manual Download: Navigate to your repository on GitHub, click the Actions tab, select the specific workflow run, and scroll down to the "Artifacts" section. Clicking the artifact name will trigger a browser download of the zip file.
- Programmatic Download: If you have a subsequent job in the same workflow that needs these files, use the
actions/download-artifactaction. This is the foundation of multi-stage pipelines where one job builds the binary and another deploys it.
Hands-on Exercise: Saving Your Test Logs
Let’s advance our project by ensuring we never lose a test report.
- Open your current workflow file (
.github/workflows/main.yml). - Add a step after your test execution step that uses
actions/upload-artifact. - Set the path to the directory where your tests output their logs or reports.
- Commit and push your changes.
- Trigger the workflow, then head to the GitHub UI to verify that the artifact appears at the bottom of the summary page.
Common Pitfalls
- Case Sensitivity: Ensure your
pathmatches the actual case of your files and folders on Linux runners. - Large Artifacts: If you upload gigabytes of data, your pipeline will slow down significantly due to network transfer times. Use artifacts for essential build outputs, not for caching dependencies (use the cache action for that instead).
- Path Nesting: When you download an artifact, it extracts into the current working directory. If you upload a directory, it will recreate that directory structure upon download. Always test your download step to ensure files land where your scripts expect them to be.
FAQ
Q: Are artifacts private? A: Yes, artifacts are subject to the same repository access permissions as your code.
Q: Can I use artifacts to pass data between different workflows? A: No. Artifacts are scoped to a single workflow run. To pass data between different runs or repositories, you would typically use an external storage provider or a container registry.
Q: Why is my artifact missing from the UI?
A: Check if the upload-artifact step actually ran. If a previous step failed and you didn't include if: always() or handle the failure, the upload step might have been skipped.
Recap
We’ve learned that while runners are ephemeral, our data doesn't have to be. By leveraging the actions/upload-artifact and actions/download-artifact actions, we ensure that our CI process produces durable, inspectable build outputs that act as a source of truth for our build status.
Up next: We will learn how to coordinate these artifacts across multiple jobs using the needs keyword in our multi-job workflows.
Work with me

CI/CD Pipeline & Docker Containerization
Ship with confidence: automated CI/CD pipelines and Docker setups so every push is tested and deployed — no more manual, error-prone releases.

AI Automation & Agentic Workflow Development
Automate the repetitive work eating your time — content pipelines, data workflows, and agentic AI tasks that run themselves.

