🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

How to Set Up CI/CD with GitLab CI in 2026: Complete Pipeline Guide

⏱️3 min read  ·  659 words

GitLab CI is one of the most powerful, fully-integrated CI/CD systems available in 2026 — no external services needed, pipelines defined in a single .gitlab-ci.yml file. This guide builds a complete pipeline from testing to production deployment.

How GitLab CI Works

GitLab CI runs pipelines defined in .gitlab-ci.yml at your repo root. Each pipeline has stages (test, build, deploy) that run sequentially. Within a stage, jobs run in parallel. Jobs execute on runners (GitLab-hosted or self-hosted).

Basic Pipeline Structure

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  NODE_VERSION: "20"

# Test stage
test:
  stage: test
  image: node:20-alpine
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run lint
    - npm run test:coverage
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

Build Stage with Docker

build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  script:
    - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" .
    - docker tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE:latest"
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
    - docker push "$CI_REGISTRY_IMAGE:latest"
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

Deploy Stage with Environments

deploy_production:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$PROD_HOST
      "cd /app && docker compose pull && docker compose up -d"
  environment:
    name: production
    url: https://example.com
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual   # require manual approval for production

Caching for Faster Pipelines

cache:
  key:
    files:
      - package-lock.json   # cache invalidates when lockfile changes
  paths:
    - node_modules/
    - .npm/

# Python:  paths: [.cache/pip, venv/]
# Go:      paths: [.go/pkg/mod/]
# Rust:    paths: [target/, .cargo/]

Parallel Matrix Builds

test:
  stage: test
  parallel:
    matrix:
      - NODE_VERSION: ["18", "20", "22"]
  image: node:$NODE_VERSION-alpine
  script:
    - npm ci
    - npm test
# Runs 3 parallel jobs testing against Node 18, 20, 22

Managing Secrets and Variables

Never hardcode secrets. Store them in Settings, then CI/CD, then Variables:

  • Mark sensitive values as Masked (hidden in logs)
  • Mark deployment secrets as Protected (only available on protected branches)
  • Use Environment scopes for different staging vs production values

Pipeline Optimization Tips

  • Use needs: to run jobs out of stage order when dependencies allow
  • Use rules: instead of only/except (modern, more flexible)
  • Use interruptible: true so new pushes cancel outdated pipelines
  • Cache aggressively — dependency install is often the slowest step
  • Use small base images (alpine variants) for faster job startup

Frequently Asked Questions

Q: GitLab CI vs GitHub Actions?
A: GitLab CI is fully integrated with GitLab (registry, environments, security scanning built in). GitHub Actions has a larger marketplace of pre-built actions. Both are excellent; choose based on where your code lives.

Q: Do I need self-hosted runners?
A: GitLab-hosted runners work for most projects. Self-hosted runners are worth it for heavy workloads, specific hardware, or private network access.

Q: How do I speed up slow pipelines?
A: Cache dependencies, use needs: for parallel execution, use smaller Docker images, split test suites with parallel:. Profile slowest jobs first.

Q: How do I handle database migrations in the pipeline?
A: Run migrations as a deploy-stage job before restarting the app. Always test migrations in staging first with a production-like database.

Q: Cache vs artifacts — what’s the difference?
A: cache speeds jobs by reusing files across runs (not guaranteed). artifacts pass files between stages within a pipeline (guaranteed).

Conclusion

GitLab CI provides a complete, integrated CI/CD system in a single YAML file. The pipeline here — test with coverage, build and push Docker images, deploy to production with manual approval — covers the full workflow for most applications. Start with a test stage, add build and deploy incrementally, and optimize with caching and parallel jobs as your pipeline grows.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇮🇳 हिन्दी🇧🇩 বাংলা