1. Resources
  2. /
  3. Plugins
  4. /
  5. renovate-buildkite-plugin

Renovate Buildkite Plugin

A Buildkite plugin that runs self-hosted Renovate in a Buildkite pipeline.

It is a port of the renovatebot/github-action GitHub Action, with the parts of GitLab’s renovate-runner templates that a scheduled pipeline needs: an ndjson log kept as an artifact, and a config-validator mode.

Quick start

Pair this plugin with altana-ai/create-github-app-token: it mints a GitHub App installation token, exports it as GITHUB_TOKEN, and revokes it when the step finishes. This plugin picks that token up with no extra configuration.

steps:
  - label: ":robot_face: renovate"
    # Renovate is a scheduled job; see Scheduling the run below.
    if: build.source == "schedule"
    concurrency: 1
    concurrency_group: renovate
    # Buildkite secrets, mapped to the environment variables the plugins read.
    # Requires agent 3.106.0 or later; values are redacted from build logs.
    secrets:
      GITHUB_APP_ID: renovate_github_app_id
      GITHUB_APP_PRIVATE_KEY: renovate_github_app_private_key
    plugins:
      # Must be listed first: its pre-command hook runs before this plugin's
      # command hook, which is what puts GITHUB_TOKEN in scope.
      - altana-ai/create-github-app-token#v0.6.0:
          app-id: "$$GITHUB_APP_ID"
          private-key: "$$GITHUB_APP_PRIVATE_KEY"
          # With no permission-* options the token inherits the app's own
          # permissions. See GitHub App permissions below for the explicit form.
      - altana-ai/renovate#v0.1.3:
          configuration-file: .buildkite/renovate-config.js

The step needs no command — this plugin provides it. The $$ keeps Buildkite from interpolating the variable at pipeline-upload time, so the auth plugin resolves it on the agent instead.

examples/pipeline.yml is the full production pipeline: a scheduled run, a dry run for manual builds, and config validation on pull requests.

[!IMPORTANT] Install the GitHub App on the runner repository as well as the repositories Renovate manages. create-github-app-token resolves the installation from the repository the build is running in, so a dedicated runner repo without the app installed fails with GitHub App is not installed on … before Renovate starts.

Renovate’s own buildkite manager updates plugin references in .buildkite/*.yml, so once this is running it keeps its own version current.

Scheduling the run

Renovate is a scheduled job, not a per-commit one. Create a dedicated pipeline for it, then add a schedule under Pipeline Settings → Schedules:

FieldValue
Cron3 * * * *
Branchmain

Give the step concurrency: 1 with a concurrency_group, so two scheduled builds can never run Renovate against the same repositories at once.

Then guard the step, or every push to the runner repository starts a real run — including the push that edits the pipeline:

if: build.source == "schedule"

That leaves the other build sources free for safer work, which is how examples/pipeline.yml is arranged:

Build sourceStep
scheduleRenovate runs for real
uiRenovate dry-runs (dry-run: full), so a config change can be checked by hand
push / PRvalidate-config only — no token is granted to that step

[!NOTE] An installation access token is valid for one hour and Renovate will not renew it, so a run that outgrows that window starts failing partway through. Keep --autodiscover-filter narrow, or split wide estates across several steps.

Configuration

Renovate

configuration-file (string)

Path to Renovate’s global configuration file, in JS or JSON format, relative to the checkout. Sets RENOVATE_CONFIG_FILE; in docker mode the file is mounted into the container. See examples/renovate-config.js.

Avoid naming it something Renovate would also read as repository config (renovate.json, .renovaterc, …).

token (string)

The token Renovate authenticates to the platform with. Either a literal value or a reference to an environment variable — "$MY_TOKEN", quoted as "$$MY_TOKEN" in the pipeline YAML so Buildkite does not interpolate it first.

Resolution order, when the option is not set:

  1. $RENOVATE_TOKEN
  2. $GITHUB_TOKEN — what create-github-app-token leaves behind

The resolved token is registered with the agent’s redactor and reaches Renovate through the environment, never as a command-line argument.

For the github-actions manager to update workflow files, the token needs the app’s Workflows: write permission (or the workflow scope, for a PAT) — that is permission-workflows: write on create-github-app-token, which is a different permission from permission-actions. Without it GitHub rejects the push with refusing to allow a GitHub App to create or update workflow, and Renovate cannot raise PRs for actions/* updates.

github-com-token (string)

Token used for github.com changelog and release lookups, so those requests are not rate-limited. Sets GITHUB_COM_TOKEN. Also accepts an environment variable reference.

extra-flags (string or list)

Extra CLI arguments for renovate, the equivalent of the GitLab runner’s RENOVATE_EXTRA_FLAGS:

extra-flags:
  - "--autodiscover=true"
  - "--autodiscover-filter=altana-ai/*"

dry-run (string)

extract, lookup or full. Sets RENOVATE_DRY_RUN — useful for a non-scheduled build that should look but not touch.

log-level (string)

Console log level: trace, debug, info, warn, error, fatal. Sets LOG_LEVEL.

log-file (string), log-file-level (string), upload-log-artifact (boolean)

Write Renovate’s machine-readable ndjson log to log-file (relative to the checkout) at log-file-level (default debug), and upload it as a Buildkite artifact unless upload-log-artifact is false. The log is kept and uploaded even when Renovate fails, which is when it is most wanted.

base-dir (string)

Directory Renovate clones repositories and stores its cache in. Sets RENOVATE_BASE_DIR. In docker mode the path must be inside one of docker-volumes — the default /tmp:/tmp already covers Renovate’s own default of /tmp/renovate.

Log the Renovate version before running it.

Config validation

validate-config (boolean, default false)

Run renovate-config-validator instead of renovate. No token is required. See Validating Renovate configuration.

validator-flags (string or list)

Files to validate. Defaults to configuration-file when not set.

Execution

mode (string, default docker)

docker or native. See Execution modes.

renovate-image (string, default ghcr.io/renovatebot/renovate)

Image to run — for example a pull-through cache such as proxy.example.com/renovate/renovate.

renovate-version (string, default 44)

Image tag, optionally with a digest. Use full for the image with every lock-file tool preinstalled (much larger), or pin it:

renovate-version: "44.24.2@sha256:90759c92793143ae7db68cd14e690109d8ace3527e17c7d188c96a1ad628282e"

env-regex (string)

Which of the agent’s environment variables are passed into the container. See Passing environment variables to Renovate.

docker-pull (string, default always)

always, missing or never, passed to docker run --pull.

docker-tty (boolean, default true)

Allocate a pseudo-TTY, which keeps Renovate’s output coloured in the Buildkite log.

docker-volumes (string or list, default /tmp:/tmp)

Volume mounts. A string may hold several, separated by ;:

docker-volumes: "/tmp:/tmp ; /opt/cache:/opt/cache"
docker-volumes:
  - /tmp:/tmp
  - /opt/cache:/opt/cache

docker-user (string)

User or UID the container runs as. Defaults to the image’s own unprivileged user; only set it (usually to root) alongside docker-cmd-file.

docker-network (string)

Docker network the container joins, e.g. host.

docker-cmd-file (string)

An executable file in the checkout to run inside the container instead of renovate, for installing extra tooling first. It is mounted at the container root. See examples/renovate-entrypoint.sh.

plugins:
  - altana-ai/renovate#v0.1.3:
      docker-cmd-file: .buildkite/renovate-entrypoint.sh
      docker-user: root

The script is responsible for dropping privileges and for forwarding "$@" if extra-flags are also in play.

mount-docker-socket (boolean, default false), docker-socket-host-path (string)

Mount the agent’s Docker socket into the container and add the container’s user to the socket’s group, so Renovate’s postUpgradeTasks can use Docker. docker-socket-host-path overrides the host path (/var/run/docker.sock).

Execution modes

docker (default) — the hook runs docker run ghcr.io/renovatebot/renovate on the agent host. This is how the GitHub Action works, and it needs nothing of the step but a Docker socket.

native — the hook runs the renovate binary already on PATH, for steps that are themselves executed inside the Renovate image. This is how the GitLab runner templates work, and it is the right mode for the Kubernetes agent stack or the docker-compose plugin. The docker-* options are ignored.

steps:
  - label: ":robot_face: renovate"
    agents:
      queue: kubernetes
    plugins:
      - kubernetes:
          podSpec:
            containers:
              - image: ghcr.io/renovatebot/renovate:44
      - altana-ai/renovate#v0.1.3:
          mode: native

Configuring Renovate itself

Only the options above belong to this plugin. Everything else is Renovate’s own configuration, and there are two ways to give it:

  1. configuration-file — global config as JS or JSON.
  2. RENOVATE_* environment variables — every self-hosted option has one, and they are forwarded to Renovate automatically.
steps:
  - label: ":robot_face: renovate"
    env:
      RENOVATE_REPOSITORY_CACHE: enabled
      RENOVATE_ONBOARDING: "false"
      RENOVATE_PLATFORM_COMMIT: enabled
    plugins:
      - altana-ai/renovate#v0.1.3: ~

For a GitHub Enterprise Server instance, set RENOVATE_ENDPOINT to https://git.example.com/api/v3.

Passing environment variables to Renovate

In docker mode only variables matching env-regex cross into the container. The default is the GitHub Action’s:

^(RENOVATE_[[:alnum:]_]+|LOG_LEVEL|LOG_FILE|LOG_FILE_LEVEL|GITHUB_COM_TOKEN|NODE_OPTIONS|NO_COLOR|(HTTPS?|NO)_PROXY|(https?|no)_proxy)$

To pass something else — credentials for a host rule, say — widen the regex. Prefer a distinct prefix over RENOVATE_, which is reserved for Renovate’s own options:

steps:
  - label: ":robot_face: renovate"
    env:
      CUSTOM_TFE_TOKEN: "$$MY_TFE_TOKEN"
    plugins:
      - altana-ai/renovate#v0.1.3:
          configuration-file: .buildkite/renovate-config.js
          env-regex: "^(RENOVATE_[A-Za-z0-9_]+|LOG_LEVEL|CUSTOM_TFE_TOKEN)$"
module.exports = {
  hostRules: [
    {
      hostType: 'terraform-module',
      matchHost: 'app.terraform.io',
      token: process.env.CUSTOM_TFE_TOKEN,
    },
  ],
};

Bash matches POSIX extended regular expressions, so \w and (?:...) are not native — but because they are what the GitHub Action’s docs use, a regex containing them is translated rather than rejected.

Variables the plugin sets itself (the token, the config file path, the log settings) are always passed, even if env-regex would not have matched them. Values are passed by name (docker run --env NAME), so no secret appears in the host’s process list.

Persisting the repository cache

Renovate’s repository cache stops it re-proposing work it already decided about. It lives under <base-dir>/cache/renovate/repository, i.e. /tmp/renovate/cache/renovate/repository by default, which the default /tmp:/tmp mount already exposes to the host.

steps:
  - label: ":robot_face: renovate"
    env:
      RENOVATE_REPOSITORY_CACHE: enabled
    cache:
      # Requires an agent with a cache backend configured.
      paths:
        - /tmp/renovate/cache/renovate/repository
    plugins:
      - altana-ai/renovate#v0.1.3: ~

Renovate reads the cache as an unprivileged user inside the container (UID 12021), so a cache restored by the agent user may need sudo chown -R 12021:0 /tmp/renovate in a pre-command hook first. On an ephemeral agent without a cache backend, leave it off: the cache is an optimisation, not state Renovate depends on.

GitHub App permissions

Renovate’s platform documentation gives the permission set a self-hosted app needs, and the permission-* option that requests each one:

GitHub App permissionScopecreate-github-app-token optionWhat loses if it is missing
Contentsread + writepermission-contents: writeEverything — branches and commits
Pull requestsread + writepermission-pull-requests: writeEverything — the PRs themselves
Issuesread + writepermission-issues: writeDependency Dashboard, config-error issues
Checksread + writepermission-checks: writeBranch status, so automerge cannot tell whether CI passed
Commit statusesread + writepermission-statuses: writeRenovate’s own statuses, e.g. renovate/artifacts
Workflowsread + writepermission-workflows: writeUpdates to files under .github/workflows
Administrationreadpermission-administration: readBranch-protection awareness for automerge decisions
Membersreadpermission-members: readTeam reviewers and assignees
Dependabot alertsreadpermission-vulnerability-alerts: readVulnerability-remediation PRs
Metadataread—Mandatory, granted implicitly

The stock Renovate app also holds Packages: read, which Renovate’s table omits. Add permission-packages: read only if your dependencies resolve from GitHub Packages or ghcr.io.

Two things to get right:

  • The app’s grants and the token’s request are separate. The app has to hold a permission, and the step has to ask for it. create-github-app-token sends an explicit permissions object as soon as one permission-* option is set, which narrows the token to exactly what is listed — so a partial list silently drops the rest. Requesting more than the app holds is a hard failure: GitHub answers 422, The permissions requested are not granted to this installation. Omitting every permission-* option makes the token inherit the app’s own set, which is the simplest correct choice for an app dedicated to Renovate.
  • An installation token covers at most one organization. Renovate documents this directly: running across several orgs needs a separate installation, token and step for each, with --autodiscover-filter scoped accordingly.

Hardening the app credentials

The private key is the one long-lived secret in this setup: anything that can read it can mint tokens for every repository the app is installed on. Two controls are worth applying.

Scope the token, not just the key. Grant the app only what GitHub App permissions lists — drop Workflows if Renovate should not touch .github/workflows — and add repositories: to create-github-app-token to scope the token to a subset of the installation. Tokens are revoked when the step ends and expire within the hour regardless.

Restrict which builds can read the key. A Buildkite secret is readable by every agent in its cluster by default. Attach an access policy to the private key so only this pipeline can fetch it — under the cluster’s secret, Access tab → Restrict access to agents matching a policy:

# Only the Renovate runner pipeline, and only when Buildkite itself started the
# build (a schedule, or someone clicking New Build).
- pipeline_id:
    - "01234567-89ab-cdef-0123-456789abcdef"
  build_source:
    - "schedule"
    - "ui"

Policy semantics: claims within a rule are ANDed, values within a claim are ORed, and rules are ORed — if no rule matches, access is denied. Prefer the first-party claims (pipeline_id, build_source, cluster_queue_id), which Buildkite generates itself; the third-party ones (pipeline_slug, build_branch, build_creator) are convenient but derive from user- or tool-supplied values, so they are weaker ground for a security boundary. pipeline_id is on the pipeline’s settings page.

Adding build_source matters here: it is what stops a pull request against the runner repository from reading the key, so an untrusted branch cannot mint a token even if it edits the pipeline. Combine it with the if: guard above — the guard decides what runs, the policy decides what can be read.

Confirm the accepted build_source values against your own pipeline before relying on the policy; the same vocabulary as build.source in step conditionals applies, and Buildkite’s docs enumerate only examples.

Validating Renovate configuration

validate-config runs renovate-config-validator instead of Renovate, which is worth a pull-request step in every repository that has Renovate config:

steps:
  - label: ":mag: renovate config"
    plugins:
      - altana-ai/renovate#v0.1.3:
          validate-config: true
          validator-flags:
            - renovate.json
            - .buildkite/renovate-config.js

In docker mode the checkout is mounted read-only and the paths are resolved inside it, so the files must live in the repository.

How it works

  1. Resolves the token from the token option, $RENOVATE_TOKEN or $GITHUB_TOKEN, and registers it with the agent’s redactor.
  2. Translates the plugin’s options into the RENOVATE_* / LOG_* environment variables Renovate reads.
  3. Logs the Renovate version.
  4. Runs Renovate — docker run with the environment, mounts and flags above, or the renovate binary on PATH in native mode.
  5. Moves the ndjson log into the checkout and uploads it as an artifact.
  6. Fails the step with Renovate’s exit code.

Because the plugin provides the step’s command hook, a command on the step itself is ignored (the hook warns when it finds one). Use docker-cmd-file, or a separate step, for work that has to happen around the Renovate run.

Requirements

  • docker on the agent (docker mode), or a step that runs inside the Renovate image (native mode)
  • buildkite-agent on PATH, for token redaction and artifact upload
  • A token with access to the repositories Renovate should manage

Troubleshooting

No token available — nothing supplied a token. Either set the token option, or list create-github-app-token before this plugin so its pre-command hook has exported GITHUB_TOKEN by the time this plugin’s command hook runs.

GitHub App is not installed on … — from the auth plugin, before Renovate starts. It resolves the installation from the repository the build is running in, so the app has to be installed on the runner repository too, not only on the repositories Renovate manages.

Authentication failure from Renovate — the token itself was rejected. Check the GitHub App is installed on the target repositories and that username/gitAuthor in the config file match the app.

Renovate fails partway through a long run — the installation token expired. They last one hour and are not renewed; narrow --autodiscover-filter or split the estate across steps.

Renovate opens PRs it already opened — the repository cache is not persisting; see Persisting the repository cache.

Nothing happens, no repositories processed — Renovate does not discover repositories by default. Give it repositories in the config file, or --autodiscover=true with an --autodiscover-filter in extra-flags.

Debugging a run — start with log-level: debug, and add log-file: renovate-log.ndjson to get the full structured log as an artifact.

Development

bats tests                     # hook tests, with docker and the agent stubbed
shellcheck hooks/* lib/*.bash tests/test_helper.bash tests/stubs/*

The tests replace docker, renovate and buildkite-agent with stubs on PATH that record their argument vectors, and assert on the command the hook builds — that command is what this plugin produces. Both commands, plus buildkite/plugin-linter, run in CI on every pull request.

Credits

Ported from renovatebot/github-action (GPL-3.0-or-later), with ideas from renovate-bot/renovate-runner (MIT).

The plugins listed on this webpage are provided for informational purposes only. They have not undergone any formal security review or assessment. While we strive to provide useful resources, we cannot guarantee the safety, reliability, or integrity of these plugins. Users are strongly advised to conduct their own security evaluations before downloading, installing, or using any plugin. By using these plugins, you acknowledge and accept any risks associated with their use. We disclaim any liability for any harm or damages arising from the use of the plugins listed.

You deserve better CI.

Get started for free with a full month of our all-access trial.

Buildkite Pipelines

Platform

  1. Pipelines
  2. Public pipelines
  3. Test Engine
  4. Package Registries
  5. Mobile Delivery Cloud
  6. Pricing

Hosting options

  1. Self-hosted agents
  2. Mac hosted agents
  3. Linux hosted agents

Resources

  1. Docs
  2. Blog
  3. Changelog
  4. Example pipelines
  5. Plugins
  6. Webinars
  7. Case studies
  8. Events
  9. Migration Services

Company

  1. About
  2. Careers
  3. Press
  4. Security
  5. Brand assets
  6. Contact

Solutions

  1. Replace Jenkins
  2. Workflows for MLOps
  3. Testing at scale
  4. Monorepo mojo
  5. Bazel orchestration

Compare

  1. Buildkite vs GitHub Actions
  2. Buildkite vs Jenkins
  3. Buildkite vs CircleCI
  4. Buildkite vs Harness
  5. Buildkite vs CloudBees
  6. Buildkite vs Blacksmith
  7. Buildkite vs Depot

Legal

  1. Terms of Service
  2. Acceptable Use Policy
  3. Privacy Policy
  4. Subprocessors
  5. Service Level Agreement
  6. Supplier Code of Conduct
  7. Modern Slavery Statement

Support

  1. System status
  2. Forum
© Buildkite Pty Ltd 2026