Passing files between jobs
A job that builds something and a later job that uses it usually need to share files: a dist/ folder, a compiled binary, a generated config. The artifacts: block on a job declares those files. Loha saves them when the job succeeds and restores them, at the same paths, before the jobs that need it start.
When you need it
Use artifacts: when a later job cannot do its work without what an earlier job produced:
buildcompiles the app, andtestandpackagerun against the compiled output.generatewrites client code, and several jobs compile against it.buildproduces a binary, anddeployships exactly that binary rather than rebuilding it.
If the later job could simply rebuild the files, or the files are only there to make a build faster, you want a cache instead. See How it differs from cache: and upload-artifact.
Example
version: '1'
on:
push:
branches: [main]
jobs:
build:
steps:
- name: Checkout
uses: loha/git-clone@v1
- name: Build
image: node:20
run: npm ci && npm run build
artifacts:
paths: [dist/, build-info.json] # relative to the workspace root; globs allowed
test:
needs: [build]
steps:
- name: Checkout
uses: loha/git-clone@v1
- name: Test
image: node:20
run: npm test # dist/ and build-info.json are already here
deploy:
needs: [test]
artifacts:
paths: [] # explicit: this job hands nothing to anyone
steps:
- name: Checkout
uses: loha/git-clone@v1
- name: Deploy
run: ./scripts/deploy.sh dist/
build lists what it produces. test and deploy list nothing about artifacts of their own: because they need build (directly or through another job), Loha restores build's files into their workspace before their own steps run.
Writing the hand-off down in artifacts: makes it explicit: it is visible in the file and in the Pipeline Builder, instead of depending on files that happen to be left behind by an earlier job.
What is saved, and when
paths is a list of paths or globs, relative to the workspace root (the checkout). The rules for each entry:
- At most 20 entries, each at most 512 characters.
- No leading
/, no..segment, no backslash, no control characters. - Globs are allowed, for example
dist/**orpackages/*/build. artifacts:accepts onlypaths. There is no per-job expiry setting.
Loha archives the matched files into one archive per job once every step of the job has succeeded. A job that fails, or one skipped by its if:, saves nothing.
A missing path fails the job
A declared path that matches no files fails the job:
Declared artifact path 'dist/' matched no files in job build.
This is deliberate. A typo in a path, or a build that quietly produced nothing, would otherwise let the pipeline continue and fail later in a confusing way. A glob that matches only . or .. counts as matching nothing.
If a job really has nothing to hand over, say so with an empty list:
artifacts:
paths: []
paths: [] is a valid declaration meaning "this job passes no files". It saves nothing and fails nothing.
What a later job receives
Every job that needs a job, directly or through a chain of needs, receives that job's files:
-
Same paths. A file saved as
dist/app.jsis restored asdist/app.js. -
After your checkout and cache. The restore runs right after the job's own
loha/git-clonestep, and after itscache:restore, so neither the checkout nor a restored cache overwrites the files. A job with no leading clone gets them after itscache:restore if it has one, otherwise before its first step. -
In order, with overwrite. Files are restored in dependency order. When two jobs saved the same path, the later job's file replaces the earlier one's.
-
Matrix shards are separate jobs. A job that
needsa matrix job receives the archive of every shard. Shards of the same matrix job do not receive each other's files, even whenmax_parallelruns them one after another. -
Skipped jobs pass nothing. A job skipped by its
if:saves no archive, and jobs that need it are skipped as well. -
An archive that cannot be restored fails the job. If an upstream job's archive exists but never finished uploading, failed, or has been deleted, the receiving job stops instead of running without the files:
Could not restore job outputs (409 JOB_OUTPUTS_NOT_READY).
Could not restore job outputs (410 JOB_OUTPUTS_GONE).JOB_OUTPUTS_GONEusually means the archive passed the retention window; run a new build.
A job receives the files of every job in its needs chain. There is no way to pick only some of them yet.
Limits
| Limit | Value |
|---|---|
| Size | 1 GiB per job archive |
| Storage | Job archives count against your workspace's artifact quota, like any other artifact |
| Retention | Deployment-wide, 14 days by default. Expired archives are deleted, so a long-lived build cannot rely on them past the window |
| Paths per job | 20 entries, 512 characters each |
| Job id length | A job that saves or restores files needs a job id of 45 characters or fewer after normalising |
Job ids are normalised by lowercasing and replacing every character that is not a letter, digit or - with -, and collapsing repeated or leading and trailing dashes. A longer id is rejected with:
Job "<id>" has a name too long for artifacts (...; the limit is 45). Shorten the job id.
Two step names are reserved inside any job: artifacts-save and artifacts-restore. Loha uses them for the hidden steps that save and restore files; naming your own step either one is rejected.
If artifact storage is not available
Artifacts need artifact storage on the Loha deployment. If it is not configured, a build whose jobs declare non-empty artifacts.paths is refused when it is triggered, with the code ARTIFACTS_UNAVAILABLE:
This pipeline passes files between jobs (artifacts:), but artifact storage is not available on this deployment.
Loha refuses rather than running without the files, because a declared artifact must never silently go missing. Ask your Loha administrator to enable artifact storage.
Seeing the files
Each job's archive is listed on the build page under Job outputs, with its size, when it expires, and a download link. They also appear on the Artifacts page under the Job outputs filter, so you can see what they cost against your quota.
In the Pipeline Builder, select a job and use its Artifacts section to edit paths.
How it differs from cache: and upload-artifact
artifacts: | cache: | loha/upload-artifact | |
|---|---|---|---|
| Purpose | Pass files to later jobs of the same build | Make builds faster | Publish a download for people |
| Lifetime | The build, plus the retention window | Across builds, per repository and branch | The retention window |
| Who consumes it | Jobs that need the producer | Any later build | A person, from the Artifacts page |
Rule of thumb: if the pipeline is wrong without the files, use artifacts:. If it is only slower, use cache:. If a human should download it, use loha/upload-artifact. A file can be both: build can save dist/ as artifacts: for the next job and also publish a zipped copy with loha/upload-artifact.
Coming from GitHub Actions or GitLab CI
The translators convert upload and download steps for you. See Migrate from GitHub Actions and Migrate from GitLab CI.