Mastering GitHub Actions: Uploading and Downloading Build Artifacts
In a typical CI/CD pipeline, jobs often run in isolation on different virtual machines. This means that any file created in one job—such as a compiled Java JAR file, a test report, or a distribution package—is lost once that job finishes. To solve this, GitHub Actions provides a mechanism called Artifacts.
Artifacts allow you to persist data after a job has completed and share that data with another job in the same workflow run. This lesson covers how to effectively use the upload-artifact and download-artifact actions to manage your build outputs.
Understanding the Artifact Workflow
Think of artifacts as a temporary storage locker. One job puts something in the locker (Upload), and another job takes it out to use it (Download). Once the workflow run is entirely finished, you can also download these files manually from the GitHub UI for inspection.
[ Job 1: Build ]
|
|--> (Step: Compile Code)
|--> (Step: Run Tests)
|--> (Step: Upload Artifact) --> [ GitHub Storage ]
|
[ Job 2: Deploy ] |
| |
|--> (Step: Download Artifact) <--------|
|--> (Step: Deploy to Server)
Uploading Build Artifacts
To save files from your runner to GitHub's servers, we use the actions/upload-artifact action. This is commonly used for compiled binaries, log files, or HTML test coverage reports.
Basic Syntax
The upload action requires a name for the artifact and the path to the file or directory you want to save.
- name: Upload Build Artifact
uses: actions/upload-artifact@v4
with:
name: production-binary
path: target/*.jar
retention-days: 5
- name: The identifier for the artifact. You will use this name to download it later.
- path: The location of the file(s). You can use wildcards like
*.jaror specify a directory. - retention-days: (Optional) How long GitHub should keep the file before deleting it to save space.
Downloading Build Artifacts
To retrieve a file uploaded by a previous job, we use the actions/download-artifact action. This is essential when you have a multi-job workflow where the "Deploy" job depends on the "Build" job.
- name: Download Build Artifact
uses: actions/download-artifact@v4
with:
name: production-binary
path: output-directory/
If you do not specify a path in the download action, the files will be downloaded into the current working directory.
Practical Java Example: Build and Package
In this example, we have two jobs. The first job compiles a Java project using Maven and uploads the JAR file. The second job downloads that JAR to simulate a deployment step.
name: Java CI with Artifacts
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: mvn clean package
- name: Archive Production Artifact
uses: actions/upload-artifact@v4
with:
name: app-jar
path: target/*.jar
test-reports:
needs: build
runs-on: ubuntu-latest
steps:
- name: Get Build Artifact
uses: actions/download-artifact@v4
with:
name: app-jar
- name: List Files
run: ls -R
Common Mistakes to Avoid
- Case Sensitivity: Artifact names are case-sensitive. If you upload as "App-Jar" and try to download "app-jar", the action will fail.
- Path Errors: Ensure the path provided in the upload step actually exists. If your build fails and doesn't produce a file, the upload step might fail or upload an empty folder.
- Job Dependencies: You cannot download an artifact in a job that runs in parallel with the upload job. Use the
needs: job_namekeyword to ensure the upload finishes first. - Disk Space: Large artifacts can quickly consume your GitHub storage quota. Always set a
retention-daysvalue for temporary files.
Real-World Use Cases
- Deployment Binaries: Compiling code once and deploying the exact same binary to Staging and Production environments.
- Test Evidence: Saving screenshots from failed Selenium or Cypress UI tests for debugging.
- Security Scans: Storing PDF or JSON reports from vulnerability scanners for compliance auditing.
- Log Persistence: Uploading verbose system logs when a build fails to help developers troubleshoot offline.
Interview Notes: Artifacts vs. Caching
A common interview question is: "What is the difference between Artifacts and Caching in GitHub Actions?"
- Artifacts: Used to share data between jobs in the same workflow run or to store build outputs for manual download. They are unique to every run.
- Caching: Used to reuse files (like dependencies in
node_modulesor.m2) across different workflow runs to speed up the build process.
Summary
Mastering artifacts is a crucial step in building professional CI/CD pipelines. By using actions/upload-artifact and actions/download-artifact, you bridge the gap between isolated jobs, ensuring that your build outputs are safely stored and easily accessible for deployment or debugging.
In the next lesson, we will explore Caching Dependencies to optimize our workflow execution time. Check out the GitHub Actions Introduction if you need a refresher on basic syntax.