iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

GitLab CI

GitLab CI runs pipelines defined in .gitlab-ci.yml. Stages run sequentially, jobs within a stage run in parallel, runners pick up jobs by tags. The model is similar to GitHub Actions, with stronger templating via include and extends.

Pipeline file with stages, caching, env, deploy

EXAMPLE
# .gitlab-ci.yml
stages: [setup, test, build, deploy]

variables:
    NODE_VERSION: "20"

default:
    image: node:${NODE_VERSION}
    cache:
        key:
            files: [package-lock.json]
        paths: [.npm/, node_modules/]

# 1) Setup — install once, share across stages via cache
install:
    stage: setup
    script:
        - npm ci --cache .npm --prefer-offline
    artifacts:
        paths: [node_modules/]
        expire_in: 1 hour

# 2) Test in parallel — fan-out
lint:
    stage: test
    needs: [install]
    script: [npm run lint]

unit:
    stage: test
    needs: [install]
    script: [npm test -- --coverage]
    coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
    artifacts:
        reports:
            junit: junit.xml
            coverage_report:
                coverage_format: cobertura
                path: coverage/cobertura-coverage.xml

e2e:
    stage: test
    needs: [install]
    image: mcr.microsoft.com/playwright:v1.44.1-jammy
    script:
        - npx playwright install --with-deps
        - npm run test:e2e

# 3) Build a Docker image — kaniko (no docker-in-docker)
build:
    stage: build
    needs: [unit, lint]
    image:
        name: gcr.io/kaniko-project/executor:v1.23.2-debug
        entrypoint: [""]
    rules:
        - if: $CI_COMMIT_TAG
    script:
        - /kaniko/executor
            --context "${CI_PROJECT_DIR}"
            --dockerfile Dockerfile
            --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
            --destination "${CI_REGISTRY_IMAGE}:latest"

# 4) Deploy to staging on main
deploy_staging:
    stage: deploy
    needs: [unit, lint]
    rules:
        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
    environment:
        name: staging
        url:  https://staging.example.com
    script:
        - ./deploy.sh staging

# 5) Deploy to prod on tag, manual approval gate
deploy_prod:
    stage: deploy
    needs: [build]
    rules:
        - if: $CI_COMMIT_TAG
    environment:
        name: production
        url:  https://example.com
    when: manual
    script:
        - ./deploy.sh prod

# 6) Include shared templates — DRY across many projects
include:
    - project: 'shared/ci-templates'
      file:    '/security.yml'
    - template: 'Security/SAST.gitlab-ci.yml'
    - template: 'Security/Dependency-Scanning.gitlab-ci.yml'

# 7) Extends — reuse job snippets
.test_base:
    stage: test
    needs: [install]
    interruptible: true

lint:
    extends: .test_base
    script: [npm run lint]

Why it matters

GitLab’s needs: graph lets you skip the rigid stage barrier — a build job can start the moment its specific upstream jobs pass, not when the whole stage clears. Big speedup on fan-out pipelines.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
# .gitlab-ci.yml
image: node:20
stages: [test, build, deploy]

test:
    stage: test
    script: npm ci && npm test

build:
    stage: build
    script: npm run build
    artifacts: { paths: [dist/] }
Try it Yourself »

Discussion

Loading…