Introduction

Renovate can be hosted as a managed app, but many teams prefer to run it themselves to keep tokens in their own vault, apply stricter maintenance windows, and tune performance for large mono-repos. This guide shows how to run Renovate in a self-hosted GitLab CI pipeline with reproducible builds, clear scheduling, and fast feedback loops.

When Self-Hosting Makes Sense

  • You need Renovate to respect maintenance windows or change freezes enforced via pipeline schedules.
  • Credentials (registry tokens, Personal Access Tokens (PATs)) must stay in a private network segment.
  • Large repos need more CPU/RAM than the shared Renovate Cloud offers.
  • You want Renovate logs and metrics shipped to your own observability stack.

Reference Architecture

The setup is intentionally split into three repos to keep concerns clear:

  1. renovate-runner: GitLab CI pipeline with group-scoped autodiscovery jobs.
  2. renovate-config: Shared Renovate presets (e.g., default.json).
  3. Application repos: Lightweight renovate.json pointing at the shared preset.

This separation lets you update schedules, runner sizing, and shared defaults without touching app repos.

Pipeline (renovate-runner/.gitlab-ci.yml)

stages:
  - renovate

.renovate_template:
  stage: renovate
  image: renovate/renovate:latest
  variables:
    RENOVATE_PLATFORM: "gitlab"
    RENOVATE_AUTODISCOVER: "true"
    RENOVATE_LOG_LEVEL: "debug"
    RENOVATE_ONBOARDING: "false"
  script:
    - renovate
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule" && ($RENOVATE_TARGET_JOB == null || $RENOVATE_TARGET_JOB == "" || $RENOVATE_TARGET_JOB == $CI_JOB_NAME)'

renovate_group_platform:
  extends: .renovate_template
  variables:
    RENOVATE_AUTODISCOVER_FILTER: "platform/**"

renovate_group_example:
  extends: .renovate_template
  variables:
    RENOVATE_AUTODISCOVER_FILTER: "example/**"

renovate_group_backends:
  extends: .renovate_template
  variables:
    RENOVATE_AUTODISCOVER_FILTER: "backends/**"

renovate_group_homepage:
  extends: .renovate_template
  variables:
    RENOVATE_AUTODISCOVER_FILTER: "homepage/**"

Key points:

  • Single template keeps image, platform, logging, and onboarding consistent.
  • Per-group jobs scope autodiscovery via RENOVATE_AUTODISCOVER_FILTER so scans stay fast and isolated.
  • Rule limits execution to scheduled pipelines and can target a single job when RENOVATE_TARGET_JOB matches CI_JOB_NAME (runs all when unset).

Shared Preset (renovate-config/default.json)

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended",
    ":dependencyDashboard",
    ":semanticCommits",
    ":prHourlyLimit4",
    ":prConcurrentLimit10"
  ],
  "labels": ["dependencies", "renovate"],
  "rebaseWhen": "behind-base-branch",
  "rangeStrategy": "replace",
  "separateMajorMinor": true,
  "separateMinorPatch": false,
  "packageRules": [
    {
      "matchUpdateTypes": ["patch"],
      "automerge": true,
      "automergeType": "pr"
    },
    {
      "matchUpdateTypes": ["minor", "major"],
      "automerge": false
    }
  ]
}

App Repo Reference (renovate.json)

{
  "extends": ["local>platform/renovate-config:default"]
}

local> tells Renovate to fetch the preset from the renovate-config repo at runtime, so changes to shared rules apply everywhere without updating app repos.

CI/CD variables

  • RENOVATE_TOKEN (masked): GitLab token for the renovate-bot user with api and read_repository.
  • RENOVATE_ENDPOINT: Override for self-managed GitLab (if not using gitlab.com). For example: https://git.yourcompany.org/api/v4
  • RENOVATE_HOST_RULES: JSON/YAML for host-specific auth (e.g., custom registries). For example [{"matchHost": "git.yourcompany.org", "token": "BgPgKXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.01.XXXXXXXXX" } ]
  • GITHUB_COM_TOKEN (masked): GitHub PAT for GraphQL to avoid rate limits; no special scopes needed.

Observability and Debugging

  • Add LOG_LEVEL=debug temporarily to inspect datasource requests and onboarding logic.
  • If MRs are not created, check branch protection and gitlabIgnoreApprovals in Renovate docs.
  • Use RENOVATE_DRY_RUN=full for safe validation before enabling schedules.
  • For stuck pipelines, cap runtime with GitLab job timeout and set RENOVATE_EXIT_CODE=1 on failure so you notice regressions.