For your scenario, there are two separate paths through your pipeline depending on the "source": a 'push' or a 'schedule'. You can get the source of the pipeline with the CI_PIPELINE_SOURCE variable. I build these paths separately at first, then combine them:

# First source: push events
stages:
  build
  deploy
  test

variables:
    BUILD_ARTIFACTS_DIR: "artifacts"

build-incremental:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: manual
      - when: never

deploy-incremental:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-incremental']
    rules:
      - if $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

test-incremental:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-incremental']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

In this path, if the source is a push, the build step will run upon manual input, otherwise it will never run. Then, the deploy-incremental step will run automatically (without waiting for other jobs or stages) as long as the source is a push, otherwise it will never run. Finally the test-incremental job will run automatically without waiting for other jobs or stages if it's a push like above.

Now we can build the schedule path:

# Scheduled path:

stages:
  build
  deploy
  test

variables:
    BUILD_ARTIFACTS_DIR: "artifacts"

build-schedule:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE === 'schedule'
        when: manual
      - when: never

deploy-schedule:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-schedule']
    rules:
      - if $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

test-schedule:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-schedule']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

This works the same way as the push path, but we check to see if the source is schedule.

Now we can combine the two paths:

Combined result:
stages:
  build
  deploy
  test

variables:
    BUILD_ARTIFACTS_DIR: "artifacts"

build-incremental:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: manual
      - when: never

build-schedule:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE == 'schedule'
        when: manual
      - when: never

deploy-incremental:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-incremental']
    rules:
      - if $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

deploy-schedule:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-schedule']
    rules:
      - if $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

test-incremental:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-incremental']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

test-schedule:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-schedule']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

A pipeline like this is tedious and takes a bit to build, but works great when you have multiple paths/ways to build the project.

Answer from Adam Marshall on Stack Overflow
🌐
GitLab
docs.gitlab.com › gitlab docs › use gitlab › use ci/cd to build your application › ci/cd yaml syntax reference
CI/CD YAML syntax reference | GitLab Docs
CI/CD variables are not supported. ... cache-job: script: - echo "This job uses a cache." cache: key: files: - Gemfile.lock - package.json paths: - vendor/ruby - node_modules · This example creates a cache for Ruby and Node.js dependencies. The cache is tied to the current versions of the ...
🌐
Reddit
reddit.com › r/gitlab › gitlab ci needs vs dependencies
r/gitlab on Reddit: GitLab CI Needs vs Dependencies
March 29, 2024 -

Hey, I'm building a simple pipeline, some steps are producing artifacts and others rely on them. I'm confused between `needs` and `dependencies` settings. Which one should be used to specify the order of execution and also pulls artifacts? It feels like there is overlap.

Thanks!

Discussions

How to define a GitLab CI job to depend on either one or one another previous job? - Stack Overflow
I want to define a pipeline to compile, deploy to target and test my project. This should happen in two distinct ways: an incremental (hopefully fast) build at each commit and a full build schedule... More on stackoverflow.com
🌐 stackoverflow.com
Gitlab dependencies in CI/CD pipeline
Hello I have 6 stages Build Image_Scan Dev Stage Prod 6 Dr_deploy in build we have 1 job build in image scan we have 3 jobs A, B, C in Dev we have A_1, A_2,B_1, B_2, C_1, C_2 in stage we have AA_1, AA_2,BB_1, BB_2, CC_1, CC_2 in Prod we have AAA_1, AAA_2,BBB_1, BBB_2, CCC_1, CCC_2 in Dr_Deploy ... More on forum.gitlab.com
🌐 forum.gitlab.com
3
0
April 24, 2023
What's the use case for GitLab CI's `dependencies`? - Stack Overflow
GitLab CI has the concept of dependencies, which "should be used in conjunction with artifacts and allows you to define the artifacts to pass between different jobs". However, "artifacts from all More on stackoverflow.com
🌐 stackoverflow.com
docker - gitlab-ci.yml: jobs dependencies - Stack Overflow
Imagine there are stages: stages: - test - build - deploy And one need to split test stage into smaller jobs like build-test-image, pytest, run-linters, etc. Jobs run-tests, run-linter... More on stackoverflow.com
🌐 stackoverflow.com
🌐
DEV Community
dev.to › zavoloklom › gitlab-ci-needs-vs-dependencies-a-practical-guide-aoi
GitLab CI: Needs vs Dependencies — A Practical Guide - DEV Community
November 16, 2024 - Dependencies define which artifacts should be available for a particular job, rather than "dependencies" in the usual sense (such as waiting for other jobs to be completed).
Top answer
1 of 3
7

For your scenario, there are two separate paths through your pipeline depending on the "source": a 'push' or a 'schedule'. You can get the source of the pipeline with the CI_PIPELINE_SOURCE variable. I build these paths separately at first, then combine them:

# First source: push events
stages:
  build
  deploy
  test

variables:
    BUILD_ARTIFACTS_DIR: "artifacts"

build-incremental:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: manual
      - when: never

deploy-incremental:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-incremental']
    rules:
      - if $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

test-incremental:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-incremental']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

In this path, if the source is a push, the build step will run upon manual input, otherwise it will never run. Then, the deploy-incremental step will run automatically (without waiting for other jobs or stages) as long as the source is a push, otherwise it will never run. Finally the test-incremental job will run automatically without waiting for other jobs or stages if it's a push like above.

Now we can build the schedule path:

# Scheduled path:

stages:
  build
  deploy
  test

variables:
    BUILD_ARTIFACTS_DIR: "artifacts"

build-schedule:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE === 'schedule'
        when: manual
      - when: never

deploy-schedule:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-schedule']
    rules:
      - if $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

test-schedule:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-schedule']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

This works the same way as the push path, but we check to see if the source is schedule.

Now we can combine the two paths:

Combined result:
stages:
  build
  deploy
  test

variables:
    BUILD_ARTIFACTS_DIR: "artifacts"

build-incremental:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: manual
      - when: never

build-schedule:
    timeout: 5h 
    stage: build
    script:
        - echo "Building"
        - ./ci/do-prep
        - echo "done."
    artifacts:
        paths:
            - $BUILD_ARTIFACTS_DIR/
    variables:
        BUILD_TOP_DIR: "/workspace/builds"
    tags:
        - yocto
    rules:
      - if: $CI_PIPELINE_SOURCE == 'schedule'
        when: manual
      - when: never

deploy-incremental:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-incremental']
    rules:
      - if $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

deploy-schedule:
    stage: deploy
    script:
        - echo "Deploying..."
        - ./ci/do-deploy
        - echo "done."
    tags:
        - yocto
    needs: ['build-schedule']
    rules:
      - if $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

test-incremental:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-incremental']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'push'
        when: always
      - when: never

test-schedule:
    stage: test
    script:
        - echo "Testing..."
        - ./ci/do-test
        - echo "done."
    tags:
        - yocto
    needs: ['deploy-schedule']
    rules:
      - if: $CI_PIPELINE_SOURCE == 'schedule'
        when: always
      - when: never

A pipeline like this is tedious and takes a bit to build, but works great when you have multiple paths/ways to build the project.

2 of 3
6

To tell Gitlab that your deploy stage needs certain artifacts from a specific job: Try naming dependencies by job name. In deploy you are defining a dependency with build which is a stage name not the one of the job you want to pick the artifact. Example:

deploy:
stage: deploy
script:
    - echo "Deploying..."
    - ./ci/do-deploy
    - echo "done."
tags:
    - yocto
dependencies:
    - build-incremental
when: manual

more info and examples here dependencies

🌐
Reintech
reintech.io › blog › managing-dependencies-artifacts-gitlab-ci
Managing Dependencies and Artifacts in GitLab CI - Reintech
May 19, 2024 - Your CI/CD pipeline is only as fast as its slowest stage. Poor dependency management means waiting 10 minutes for npm to reinstall the same packages on every commit. Inefficient artifact handling means rebuilding components that haven't changed or losing critical build outputs between pipeline stages. GitLab CI provides robust mechanisms for managing both dependencies and artifacts through the .gitlab-ci.yml configuration file.
🌐
GitLab
forum.gitlab.com › gitlab ci/cd
Gitlab dependencies in CI/CD pipeline - GitLab CI/CD - GitLab Forum
April 24, 2023 - Hello I have 6 stages Build Image_Scan Dev Stage Prod 6 Dr_deploy in build we have 1 job build in image scan we have 3 jobs A, B, C in Dev we have A_1, A_2,B_1, B_2, C_1, C_2 in stage we have AA_1, AA_2,BB_1, BB_2, CC_1, CC_2 in Prod we have AAA_1, AAA_2,BBB_1, BBB_2, CCC_1, CCC_2 in Dr_Deploy we have AAAA_1, AAAA_2,BBBB_1, BBBB_2, CCCC_1, CCCC_2 if the build job fails total stages should be skipped in image scan jobs A, B, C if any fails it should skip respective jobs for example i...
🌐
GitLab
docs.gitlab.com › gitlab docs › use gitlab › secure your application › detect › dependency list
Dependency list | GitLab Docs
If the dependency scanning CI/CD job is configured, discovered licenses are displayed on this page.
Find elsewhere
🌐
GitLab
docs.gitlab.com › gitlab docs › use gitlab › use ci/cd to build your application › ci/cd components
CI/CD components | GitLab Docs
Limit dependency on caches and artifacts from other jobs: Only use cache and artifacts from other jobs in CI/CD components if absolutely necessary
🌐
GitLab
gitlab.com › gitlab.org › repository
lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml · master · GitLab.org / GitLab · GitLab
GitLab is an open source end-to-end software development platform with built-in version control, issue tracking, code review, CI/CD, and more. Self-host GitLab on your own servers, in a...
🌐
Renovate Docs
docs.renovatebot.com › modules › manager › gitlabci
Automated Dependency Updates for GitLab CI/CD - Renovate Docs
{ "managerFilePatterns": [ "/\\.gitlab-ci\\.ya?ml$/" ] } Extracts Docker dependencies from gitlab-ci.yml files.
🌐
GitLab
about.gitlab.com › blog › engineering › the basics of ci: how to run jobs sequentially, in parallel, or out of order
Running CI jobs in sequential, parallel, and custom orders
April 24, 2024 - This is where Directed Acyclic ... has a special keyword needs, which creates dependencies between jobs, and allows jobs to run earlier, as soon as their dependent jobs complete....
🌐
GitLab
docs.gitlab.com › gitlab docs › use gitlab › use ci/cd to build your application › ci/cd yaml syntax reference › needs
Make jobs start earlier with needs | GitLab Docs
The needs: project and needs: pipeline keywords are not used to specify job dependencies. Use needs: project to fetch artifacts from other pipelines.
🌐
GitLab
docs.gitlab.com › gitlab docs › use gitlab › use ci/cd to build your application › pipelines
CI/CD pipelines | GitLab Docs
To get started with your first pipeline, see Create and run your first GitLab CI/CD pipeline. Pipelines can be configured in many different ways: Basic pipelines run everything in each stage concurrently, followed by the next stage. Pipelines that use the needs keyword run based on dependencies ...
🌐
GitLab
gitlab.com › gitlab.org › repository
lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml · master · GitLab.org / GitLab · GitLab
# List of available variables: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#available-cicd-variables variables: # Setting this variable affects all Security templates # (SAST, Dependency Scanning, ...) SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products" # DS_EXCLUDED_ANALYZERS: "" DS_EXCLUDED_PATHS: "spec, test, tests, tmp, node_modules" DS_MAJOR_VERSION: 6 DS_SCHEMA_MODEL: 15 dependency_scanning: stage: test script: - echo "$CI_JOB_NAME is used for configuration only, and its script should not be executed" - exit 1 artifacts: access: 'developer
🌐
Medium
medium.com › @dhilipsingh92 › gitlab-cicd-rules-artifacts-cache-expire-in-dependencies-parallel-retry-timeout-when-tag-8fb4eb7832eb
GitLab CICD -Rules ,Artifacts ,Cache ,Expire_in, Dependencies, Parallel, Retry, Timeout, When, Tag ,allow_Failure , Approval | by Dhilipsingh G | Medium
June 25, 2025 - The expire_in setting in GitLab ... expire_in: 1 hour # Change as needed ... Dependencies define which artifacts should be available for a particular job, rather than “dependencies” in the usual sense (such as waiting ...
🌐
Phylum
docs.phylum.io › integrations › gitlab ci integration
GitLab CI Integration | Phylum Documentation
August 28, 2025 - Once configured for a repository, the GitLab CI integration will provide analysis of project dependencies from manifests and lockfiles. This can happen in a branch or tag pipeline as a result of a push or in a Merge Request (MR) pipeline.
🌐
GitLab
docs.gitlab.com › gitlab docs › use gitlab › use ci/cd to build your application › pipelines › pipeline architectures
Pipeline architecture | GitLab Docs
If efficiency is important and you want everything to run as quickly as possible, you can use the needs keyword to define dependencies between your jobs. When GitLab knows the dependencies between your jobs, jobs can run as fast as possible, even starting earlier than other jobs in the same stage.
🌐
Renovate Docs
docs.renovatebot.com › modules › manager › gitlabci-include
Automated Dependency Updates for GitLab CI/CD include - Renovate Docs
{ "managerFilePatterns": [ "/\\.gitlab-ci\\.ya?ml$/" ] } Extracts "includes" dependencies from gitlab-ci.yml files.