We often see teams spending hours rebuilding artifacts due to incorrect CI/CD configuration. Instead of passing a compiled binary between jobs, they re-run all build steps. The result: pipeline time increases and developers wait. Incorrect artifact configuration leads to unnecessary CI minute costs and developer time. In this article, we'll cover artifact configuration in CI/CD for GitLab CI and GitHub Actions.
Recently, a microservices team approached us: their pipeline took 45 minutes because each service was rebuilt from scratch on every commit. After configuring artifact passing, the time dropped to 12 minutes—a 73% reduction, saving the team a significant portion of their CI budget. Such savings are possible if artifacts are configured correctly and implicit rebuilds are eliminated.
Why can't artifacts be replaced by cache?
They are often confused. Cache is for accelerating repetitive operations (dependencies, intermediate compilation files). Artifacts are for passing results between jobs within a single pipeline.
- Cache: lives between pipeline runs, can be stale, hit is not guaranteed.
- Artifact: created in the current pipeline, passed to subsequent jobs with certainty, deleted according to
expire_in.
Comparison table:
| Parameter | Cache | Artifact |
|---|---|---|
| Purpose | Accelerate repeated steps | Pass results between jobs |
| Lifetime | Between pipelines | Within a single pipeline (or longer) |
| Freshness guarantee | No | Yes |
| Typical data | node_modules/, .m2/repository |
dist/, *.jar, reports/*.xml |
How do artifacts speed up the pipeline?
Proper artifact configuration allows building DAG pipelines where jobs start immediately after receiving necessary artifacts, without waiting for an entire stage to finish. As a result, execution time is reduced by 30–70%. For example, in one project, we replaced a linear pipeline with a DAG using artifact passing—the pipeline ran in 8 minutes instead of 25. The average monthly savings amounted to $630–910 due to reduced CI minute costs.
How to configure artifacts in GitLab CI?
---
build:
stage: build
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
- package.json
expire_in: 1 hour
when: always
test:
stage: test
needs:
- job: build
artifacts: true
script:
- npm run test
artifacts:
reports:
junit: reports/junit.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
deploy:
stage: deploy
needs:
- job: build
artifacts: true
script:
- rsync -av dist/ user@server:/var/www/app/
needs with artifacts: true—the deploy job downloads artifacts from build without waiting for intermediate stages. This is a DAG pipeline—a faster alternative to linear stages. More details in GitLab CI documentation.
How to pass artifacts in GitHub Actions?
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: frontend-dist-${{ github.sha }}
path: dist/
retention-days: 1
if-no-files-found: error
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: frontend-dist-${{ github.sha }}
path: dist/
- run: ./scripts/deploy.sh dist/if-no-files-found: error is an important setting. By default, upload succeeds even if no files exist, and the next job downloads an empty artifact. Better to fail explicitly. retention-days: 1 for intermediate build artifacts—they are only needed within this pipeline. For release artifacts, set longer. More details in GitHub Actions documentation.
Comparison between GitLab CI and GitHub Actions
| Parameter | GitLab CI | GitHub Actions |
|---|---|---|
| Base syntax | artifacts in job |
actions/upload-artifact step |
| Retention period | expire_in (max 30 days for free) |
retention-days (max 90 days for free) |
| DAG pipelines | needs with artifacts: true |
needs: at the job level |
| Reports | Built-in support for JUnit and Cobertura | Via custom actions |
| External storage integration | Via scripts | Via actions or scripts |
When to use external storage?
For artifacts needed outside a single pipeline—release binaries, Docker images, npm packages—CI storage is not suitable. Here you need external storage:
- GitHub Releases / GitLab Releases—artifacts attached to a tag, accessible via API.
- S3 / GCS—for binaries and static files with versioning.
- Nexus / Artifactory—for Maven, npm, Docker in corporate infrastructure.
- Docker Registry—images tagged with git SHA and/or semver tag.
Publishing to Nexus from GitLab CI:
---
publish:
stage: publish
needs:
- job: build
artifacts: true
script:
- mvn deploy -s .mvn/settings.xml \
-Dnexus.url=$NEXUS_URL \
-Dnexus.username=$NEXUS_USER \
-Dnexus.password=$NEXUS_PASS \
-DskipTests
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+/'
---
Deploying to Nexus only on tags is a good policy. Storing artifacts in external storage reduces CI minute costs and frees up space in CI.
Step-by-step artifact configuration plan
- Audit current pipelines—identify all places where artifacts are created and consumed.
- Determine necessary artifacts—separate intermediate (dist/, reports/) from final (release binaries).
- Configure artifacts/upload-artifact—set correct paths, retention periods, and save conditions.
- Integrate with external storage—connect S3, Nexus, or Docker Registry for long-term storage.
- Test and monitor—verify artifacts are passed correctly, set up alerts for empty artifacts.
What's included in artifact configuration work
We assess your current pipeline, identify bottlenecks, and configure artifact passing turnkey. Result:
- Pipeline audit: what artifacts are created, how long they live, where they are stored.
- Configuration of
artifacts/upload-artifactwith optimalexpire_inandretention-days. - Integration with external storage (S3, Nexus, Docker Registry) if needed.
- Documentation on the process and recommendations for further optimization.
- Support for one month after implementation.
We have helped teams reduce pipeline time by 30–70% through proper artifact configuration. Contact us for a pipeline audit—we evaluate your current configuration in one day and propose an optimal solution. Order turnkey artifact configuration and start saving time and budget today.
Typical mistakes when configuring artifacts
- Too long retention:
expire_in: neverclogs storage. Set reasonable limits. - Missing
if-no-files-found: errorin GitHub Actions—the next step may silently deploy an empty artifact. - Passing dependencies instead of results: cache
node_modulesseparately, don't drag them as artifacts.







