Skip to main content

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:

  • build compiles the app, and test and package run against the compiled output.
  • generate writes client code, and several jobs compile against it.
  • build produces a binary, and deploy ships 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​

.loha.yml
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/** or packages/*/build.
  • artifacts: accepts only paths. 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.js is restored as dist/app.js.

  • After your checkout and cache. The restore runs right after the job's own loha/git-clone step, and after its cache: restore, so neither the checkout nor a restored cache overwrites the files. A job with no leading clone gets them after its cache: 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 needs a matrix job receives the archive of every shard. Shards of the same matrix job do not receive each other's files, even when max_parallel runs 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_GONE usually 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​

LimitValue
Size1 GiB per job archive
StorageJob archives count against your workspace's artifact quota, like any other artifact
RetentionDeployment-wide, 14 days by default. Expired archives are deleted, so a long-lived build cannot rely on them past the window
Paths per job20 entries, 512 characters each
Job id lengthA 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
PurposePass files to later jobs of the same buildMake builds fasterPublish a download for people
LifetimeThe build, plus the retention windowAcross builds, per repository and branchThe retention window
Who consumes itJobs that need the producerAny later buildA 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.