12 Tips to Self-host Renovate Bot

Updating dependencies is boring. Despite its importance, we always find excuses to avoid updating them in the phrase of “if it ain't broke, don't fix it” or “there are more important features to work on”. Over time, the maintainability of the projects deteriorates. The team ends up with a 3-year-old dependency where no one is brave enough to bump it.

So, what’s the solution? Let the bots do our boring job!

In this article, you will learn tips on running a self-hosted Renovate bot with GitLab (self-hosted) as an example. If you’re looking for a guide on how to start using Renovate on GitHub, I’d highly recommend you read this instead.

TL;DR

  • Why use Renovate
  • Getting started on self-hosted Renovate (GitLab as an example)
  • How to run Renovate locally
  • Debugging Renovate jobs
  • 12+ Useful Renovate bot tips (updated 2023)

Why Use Renovate

In short, Renovate helps to update project dependencies (private or third-party) automatically.

How? Renovate parses our projects’ dependency management files such as package.json, pyproject.toml, go.mod file and raise a pull/merge request (PR/MR) with the updated dependencies accordingly.

Renovate is highly customizable via a simple configuration file. It also supports a wide range of package managers.

Today, Renovate supports many other VCS hosts such as Bitbucket, Gitea, and even Azure DevOps. On top of that, it’s used by a lot of popular development communities or companies such as Uber, GitLab, Netlify, Apollo GraphQL, etc.

Highlight

Personally, I think the best part about Renovate is its ability to auto-merge PRs/MRs.

That aside, the flexibility provided by the packageRules feature which is used to apply rules to specific dependencies (in individual or group) is incredibly handy to reduce noise.

How To Run Self-hosted Renovate on GitLab

To run Renovate on self-hosted GitLab, you’ll need a GitLab project (i.e. repository in the following). This bot repository will be used to host GitLab runners which run Renovate for your other projects.

Next, assuming that you already have GitLab runners installed and set up, you’ll need the following in the bot project:

  1. Configure the following CI/CD variables:
  • RENOVATE_TOKEN — GitLab Personal Access Token (PAT) with scopes: read_user, api, and write_repository.
  • GITHUB_COM_TOKEN —  GitHub PAT with minimum scope.

2. config.js  – Here's a simple example (source):

module.exports = {
  endpoint: 'https://your.gitlab.com/api/v4/',
  token: process.env.RENOVATE_TOKEN,
  platform: 'gitlab',
  onboardingConfig: {
    extends: ['config:base'],
  },
  repositories: ['username/repo', 'orgname/repo'],
};
If you need a more complex example, check this out!

3. .gitlab-ci.yml – If you need a more complex example, see this example from the GitLab team. Otherwise, here’s a minimal example; do update accordingly:

image: renovate/renovate:36.57.4 # prefer pinned instead of `latest`

variables:
    LOG_LEVEL: info # optional: set to "debug" or "trace" from CI/CD variables setting to override

renovate:on-schedule:
    tags:
        - your-gitlab-runner-tag-if-any
    rules:
        - if: $CI_PIPELINE_SOURCE == "schedule"
          when: always
        - if: $CI_PIPELINE_SOURCE == "web"
          when: always

    script:
        - renovate $RENOVATE_EXTRA_FLAGS # optional: set this under your CI/CD variables
.gitlab-ci.yml

4. Lastly, you’ll need to run Renovate at regular intervals (e.g. every hour) using the GitLab project’s CI/CD Schedules feature. Do note that this is different from Renovate’s own schedule.

💡
Check the source for more details. However, the steps above should be sufficient.

How To Run Renovate Locally

While I was working with a large repository (60+ GiB), each Renovate job may take many hours, sometimes a day to complete. Having the ability to run Renovate locally saves me a bunch of time when it comes to experimentation and debugging.

First, create a minimum reproducible example (MRE) repository. Then, update your config.js to target or discover the MRE repository. To run Renovate locally:

  1. It’s a lot easier to just use Docker. So, make sure you’ve installed Docker.
  2. To start, you’ll need to ensure that these environment variables are being exported in your shell:
export RENOVATE_TOKEN="aa11bb22cc" # GitLab Personal Access token (PAT)
export GITHUB_COM_TOKEN="cc33dd44ee" # GitHub PAT

3. Next, update your config.js accordingly. You’ll need to update your target repositories accordingly. You could instead choose to autodiscover repositories but you'll end up running it on multiple repositories instead of just one.

4. Finally, you can run Renovate using the following. To grab the latest Renovate version, check out Docker Hub. Do change the following command accordingly:

docker run \
    --rm \
    -e LOG_LEVEL="debug" \
    -e GITHUB_COM_TOKEN="$GITHUB_COM_TOKEN" \
    -v "/path/to/local/config.js:/usr/src/app/config.js" \
    renovate/renovate:"36.57.4" \
    --token "$RENOVATE_TOKEN" \
    --dry-run="true"
In case you need more comprehensive logs, try setting LOG_LEVEL=”trace” instead

With this, testing the Renovate configuration in a fast-feedback loop manner is now possible.

To perform an actual run, update --dry-run="false".

Useful Renovate Bot Tips

General

  1. If you are unsure whether Renovate supports a certain functionality, always check out their FAQ page first. Chances are it’s already there.
  2. To disable updates for a specific package or library simply set enabled: false under their respective packageRule. Example:
module.exports = {
    endpoint: 'https://your.gitlab.com/api/v4/',
    token: process.env.RENOVATE_TOKEN, // Set from CI/CD variable
    platform: 'gitlab',
    repositories: [
        {
            repository: 'john/next-generation-repo',
            packageRules: [
                {
                    description: 'Disable MAJOR update types',
                    matchUpdateTypes: ['major'],
                    enabled: false,
                },
            ],
        },
    ],
}
Example of how to disable all 'major' type updates. This can be scoped down to individual dependency

4. Need to run some custom task or script after upgrading (e.g. a script that posts messages to Slack)? Try postUpgradeTasks.

5. Setup a separate GitLab CI job for validating Renovate config using renovate-config-validator:

# ...

renovate:validate:
    tags:
        - your-gitlab-runner-tag-if-any
    stage: lint
    script:
        - renovate-config-validator
    rules:
        - if: $CI_PIPELINE_SOURCE == "merge_request_event"
          changes:
              - config.js
          allow_failure: false
.gitlab-ci.yml

6. Renovate is creating too many MRs?! Check out these noise reduction tips!

7. You can customize your organization's commit message, branch prefix, PR titles, etc. to fit your organization's push rules.

8. Set osvVulnerabilityAlerts to true to check if extracted dependencies have known vulnerabilities. It prevents the use of risky dependencies, maintains codebase quality, and saves you from future fixes. Customize it using vulnerabilityAlerts!

💡
Not sure how to get the most out of Renovate quickly? Check out this Renovate bot cheat sheet instead of the verboseness of the official Renovate doc.

Few repositories

  1. Keep project-specific Renovate configs on the bot repository config.js instead of having renovate.json in every repository. This allows for Renovate-related configs to be centralized and abstracted away to a single MRE only.
  2. Set onboarding: false under module.exports to avoid creating renovate.json in other repositories.
  3. Set requireConfig: 'optional' as the configs will all be within your config.js.

Many repositories

  1. If you have hundreds if not thousands of repositories to renovate, do use the autodiscover feature instead of adding them directly to your config.js.
  2. Sequentially renovating each repository is going to take a long time. You may want to run Renovate in parallel.
  3. Here, set onboarding: true to automatically onboard new repositories.
  4. Set requireConfig: 'required'.
  5. Remember to set your own onboardingConfig under the config.js.
  6. Consider creating sharable config presets for each team/organization in your company and extend them in your onboardingConfig.
module.exports = {
    endpoint: 'https://your.gitlab.com/api/v4/',
    gitAuthor: 'Renovate Bot <[email protected]>',
    hostRules: [
        {
            matchHost: 'github.com',
            token: process.env.GITHUB_TOKEN,
        },
        {
            matchHost: 'gitlab.myteksi.net',
            token: process.env.RENOVATE_TOKEN,
        },
    ],
    onboarding: true,
    onboardingConfig: {
        $schema: 'https://docs.renovatebot.com/renovate-schema.json',
        extends: ['local>group/subgroup/repo:default.json5'], // custom sharable config preset
    },
    persistRepoData: true,
    platform: 'gitlab',
    requireConfig: 'required',
    token: process.env.RENOVATE_TOKEN,
}

// Add code to run Renovate in parallel: https://github.com/renovatebot/renovate/discussions/13172#discussioncomment-2341331
config.js

Debugging Renovate jobs

When it comes to self-hosted solutions, there’s no running away from debugging your jobs. There could be scenarios where you’ll need to test connections to your private registry, proxy, etc.

Here are a couple of helpful tips:

  1. Try running Renovate locally targeting a single repository to have a faster feedback loop instead of relying on your CI/CD pipelines. Plus, running locally is practically free!
  2. Use trace LOG_LEVEL in case debug doesn’t give you enough information.
  3. In case you’re working on some bespoke use cases or facing odd encounters/bugs, try Google searching with the prefix “site:github.com/renovatebot/renovate <your keywords or phrases>”. (example). In most cases, you’ll find that there are already others who have filed a similar discussion or issue.

Dealing with a large repository (e.g. GB in size)

  1. If you have a Go monorepo, consider using a Go module proxy like Athens.
  2. Under your GitLab project’s CI/CD General pipelines settings, you may want to increase your job timeout (e.g. "10 hours") as Renovate may take a long time on an uncached run on large repositories.
  3. On some occasions, you may run into ERROR: Disk space error - skipping. Here, you may want to provision a runner with an increased disk size. E.g. if you are using AWS EC2, try to increase the size of the volume.
  4. You may want to set persistRepoData: true for faster git fetch between runs.
  5. If you attempt to run Renovate on a large repository, you may encounter a SIGTERM signal (which can be seen in your Renovate job log) due to timeout. To cope with this, increase the executionTimeout setting in your config.js.
module.exports = {
    endpoint: 'https://your.gitlab.com/api/v4/',
    executionTimeout: 1440, // minutes
    token: process.env.RENOVATE_TOKEN,
    platform: 'gitlab',
    persistRepoData: true,
    repositories: ['john/repo'],
}
config.js

Conclusion

Over the past few months, I have been using Renovate extensively; on GitHub, and self-hosted GitLab. Today, I am using Renovate on most of my active projects on GitHub to automate dependency updates. So far, Renovate was able to fit 99% of my use cases.

Keeping our project dependencies up-to-date is often overlooked. Yet, overlooking such work often comes at a great cost. The fact that we can leverage Renovate’s ability to do this grunt work is quite a blessing.

I hope this article saves you enough time instead of having you groom through pages of GitHub discussions and issues. Thanks for reading!

Hosted on Digital Ocean.