Renovate automates the updates of your software dependencies by creating testable, traceable and mergeable Pull Requests. This guide teaches you how to install, configure and secure it. You will be able to adapt the update strategies to your project (scheduling, automerge, grouping) and harden your installation against supply chain attacks. Prerequisites: Node.js 24.11+ installed and access to a Git repository (GitHub, GitLab, Bitbucket or other).
What you will learn
- Install Renovate and run a first local dry-run.
- Configure presets, scheduling and automerge.
- Customize updates with packageRules, custom managers and grouping.
- Secure a self-hosted installation against supply chain attacks.
- Run Renovate in CI/CD (GitHub Actions, GitLab CI).
What is Renovate?
Renovate continuously watches the libraries of your project, checks whether newer versions are available, and prepares an automatically tested update, ready to merge.
Renovate is an open source tool (AGPL license) maintained by Mend.io. It
analyzes your dependency files (package.json, Dockerfile,
docker-compose.yml, requirements.txt, go.mod, pom.xml, Terraform files,
Ansible playbooks, GitHub Actions, and many more), detects outdated versions, and automatically creates Pull Requests (PRs) with the
matching updates.
| Without Renovate | With Renovate |
|---|---|
| Manual version checks | Automatic update detection |
| Risk of forgetting dependencies | Coverage of all recognized dependency files |
| No traceability of decisions | Full history in the PRs |
| Vulnerabilities that stay undetected for a long time | Update proposed as soon as a fixed version is published |
Renovate supports a very large number of package managers (called managers, the full list is in the documentation): JavaScript (npm, Yarn, pnpm), Python (pip, Poetry, Pipenv), Java (Maven, Gradle), Go, Rust, Ruby, .NET, PHP, Helm, Terraform, Ansible, Docker, GitHub Actions, and many more.
Prerequisites
Before starting, check that you have:
- Node.js 24.11 or higher: Renovate is installed through npm. Check with
node -v. - A Git repository hosted on GitHub, GitLab, Bitbucket, Azure DevOps, Forgejo or Gitea.
- A Personal Access Token (PAT) with the necessary rights on your platform (detailed below).
- Basic Git knowledge: knowing what a branch and a Pull Request are.
How Renovate works
Understanding how Renovate works internally helps you configure it better. On each run, Renovate goes through five phases:
Phase 1, Initialization. Renovate clones the repository, reads the configuration
(renovate.json) and resolves the extended presets. It checks whether the repository is already
onboarded (that is, whether it has a configuration file).
Phase 2, Dependency extraction. The managers go through the files
of the project to identify all the declared dependencies. Each manager knows how
to read a specific format: the npm manager reads package.json, the
dockerfile manager reads FROM instructions, the terraform manager reads the
required_providers blocks, and so on.
Phase 3, Update lookup. For each extracted dependency, Renovate queries the matching datasource (the npm registry, Docker Hub, PyPI, etc.) to find the available versions. It compares the current version with the published versions and determines the applicable updates.
Phase 4, Writing the updates. Renovate generates the necessary changes: it creates branches, updates the dependency files (including the lock files), and opens the Pull Requests on the platform.
Phase 5, Finalization. Renovate updates the Dependency Dashboard (if enabled), handles the automerge of the PRs that passed the tests, and cleans up the stale branches.
The diagram shows these five phases in the order of a run. The highlighted phase, lookup, is the one that queries the registries: it decides which updates apply.
Installation and first run
-
Install Renovate globally
Open a terminal and install the npm package:
Terminal window npm install -g renovateCheck: run
renovate --version. You should see a version number (for example43.278.5). -
Create the Personal Access Tokens
Renovate needs two tokens to work:
RENOVATE_GITHUB_COM_TOKEN: a classic PAT on github.com with thepublic_reposcope. It is used to fetch changelogs and avoid API limits.RENOVATE_TOKEN: a PAT with therepoandworkflowscopes on the target repository.
RENOVATE_GITHUB_COM_TOKEN: the same GitHub token as above (for changelogs).RENOVATE_TOKEN: a GitLab PAT with theapi,write_repositoryandread_registryrights.
Export the tokens in your terminal:
Terminal window export RENOVATE_GITHUB_COM_TOKEN="ghp_your_github_token"export RENOVATE_TOKEN="your_platform_token"You will still come across the old name
GITHUB_COM_TOKENin existing configurations. The Renovate documentation declares it deprecated, and it will be removed in an upcoming major version. It is still read in the meantime, and it takes precedence over the new name if both are defined: delete it when you switch toRENOVATE_GITHUB_COM_TOKEN, otherwise the old token is the one used. -
Create the configuration file
At the root of your repository, create a
renovate.jsonfile:{"$schema": "https://docs.renovatebot.com/renovate-schema.json","extends": ["config:recommended"]}The
config:recommendedpreset enables the settings recommended by the Renovate team: grouping of non-major updates by monorepo, a limit on concurrent PRs, and activation of the Dependency Dashboard. -
Run a local dry-run
Before running Renovate on a real repository, test it in local mode to see what it detects without creating any branches or PRs:
Terminal window LOG_LEVEL=debug renovate --platform=local --dry-run=lookupThis mode analyzes the current directory, identifies the dependencies and the available updates, then stops without modifying anything. Browse the logs to check that Renovate detects your files properly.
-
Run Renovate on a remote repository
Once you are happy with the dry-run, run Renovate on a real repository:
Terminal window renovate --platform=github your-org/your-repoOr for GitLab:
Terminal window renovate --platform=gitlab --endpoint=https://gitlab.com/api/v4 your-org/your-repoOn the first run, Renovate creates an onboarding PR that proposes a
renovate.jsonfile. Merge this PR to enable Renovate on your repository.
Basic configuration
The configuration files
Renovate looks for its configuration in one of these files, in order of priority:
| File | Format |
|---|---|
renovate.json | Standard JSON |
renovate.json5 | JSON5 (comments allowed) |
.renovaterc | JSON or JSON5 |
.renovaterc.json | JSON |
renovate section in package.json | JSON |
In practice, renovate.json is the most common choice. If you prefer to add comments to document your configuration, use the
JSON5 format with renovate.json5.
Understanding presets
Presets are reusable configurations. Instead of configuring everything by hand, you extend an existing preset: you start from a consistent base and only override what differs.
The most common built-in presets:
| Preset | Role |
|---|---|
config:recommended | Recommended base configuration |
config:best-practices | Stronger recommendations (includes minimumReleaseAge for npm) |
:dependencyDashboard | Enables the dependency dashboard (included in config:recommended) |
schedule:nonOfficeHours | Limits updates to outside office hours |
group:allNonMajor | Groups all minor and patch updates into a single PR |
:automergeDigest | Automerges Docker digest updates |
Here is an example combining several presets:
{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:recommended", "schedule:nonOfficeHours", ":automergeDigest" ]}Update strategies
Semantic versioning (SemVer)
Most ecosystems follow the SemVer convention:
MAJOR.MINOR.PATCH. Each type of update carries a different risk:
- Patch (e.g. 1.2.3 → 1.2.4): bug fixes. Very low risk.
- Minor (e.g. 1.2.3 → 1.3.0): new backward-compatible features. Low risk.
- Major (e.g. 1.2.3 → 2.0.0): changes that may break backward compatibility. High risk.
Renovate distinguishes these three types and lets you configure a different behavior for each. The config:recommended preset automatically separates major updates from the others.
Adapting the strategy by update type
Here is a typical configuration that automatically merges patches and minors while keeping majors for a manual review:
{ "extends": ["config:recommended"], "packageRules": [ { "description": "Automerge patches and minors (excluding v0.x)", "matchUpdateTypes": ["minor", "patch"], "matchCurrentVersion": "!/^0/", "automerge": true } ]}The matchCurrentVersion: "!/^0/" condition excludes packages in 0.x versions, because SemVer allows breaking changes on any update before version 1.0.0. The /^0/ pattern is a regular expression that designates versions starting with 0, and the leading ! inverts it.
The range strategy
The rangeStrategy option controls how Renovate modifies the version
constraints in your files. The possible values are:
| Strategy | Behavior | Typical use |
|---|---|---|
bump | Raises the lower bound (^1.2.3 → ^1.3.0) | Applications with a lock file |
replace | Widens the range if possible (^1.2.3 → ^1.3.0 if compatible) | Published libraries |
pin | Pins the version exactly (^1.2.3 → 1.3.0) | Maximum reproducibility |
widen | Widens the range (^1.2.3 → ^1.2.3 || ^2.0.0) | Libraries supporting several majors |
auto | Lets Renovate decide depending on the context | Default value |
For an application project (not published as a library), the bump strategy is generally the best choice because it makes updates explicit in the lock file.
Scheduling updates
By default, Renovate is "always on": it creates PRs as soon as it finds an update. This can become noisy on projects with many
dependencies. The schedule option lets you control the execution windows.
Setting a time zone
Renovate uses UTC by default. To use your local time, configure the time zone with an IANA identifier:
{ "timezone": "Europe/Paris"}Scheduling examples
Renovate recommends the cron syntax (5 fields) for schedules.
The asterisk * is mandatory for the minutes because Renovate does not support minute granularity:
{ "extends": ["config:recommended"], "timezone": "Europe/Paris", "schedule": ["* 0-4 * * 1-5", "* * * * 0,6"]}This configuration means: run the updates on weekdays between midnight and 5 a.m., and at any time on weekends.
Other common examples:
| Need | Cron | Equivalent preset |
|---|---|---|
| Outside office hours | * 0-4,22-23 * * 1-5 + * * * * 0,6 | schedule:nonOfficeHours |
| Weekends only | * * * * 0,6 | schedule:weekends |
| Monday morning before 6 a.m. | * 0-5 * * 1 | none |
| Quarterly, on the 1st of the month | * * 1 */3 * | none |
Limiting the frequency for a specific package
Some libraries publish very often (AWS SDK, TypeScript types...). You can apply a dedicated schedule to them to reduce the noise:
{ "packageRules": [ { "description": "AWS SDK: weekly updates only", "matchPackageNames": ["@aws-sdk/**"], "schedule": ["* 21-23 * * 0"] } ]}Automerge: merging automatically
Automerge lets Renovate merge a PR without human intervention as soon as the CI tests pass. This feature is ideal for low-risk updates: devDependencies patches, lock file updates, or Docker digests.
When to enable automerge
The Renovate team recommends enabling automerge for any update that you would systematically merge anyway. In practice, this often covers:
- devDependencies (linters, test tools, formatters)
- Minor and patch updates on well-tested projects
- Lock file maintenance (refresh with no change of the declared version)
- Docker digests (hash update with no tag change)
Automerge configuration examples
Automerge of linter devDependencies:
{ "packageRules": [ { "description": "Automerge dev tools", "matchDepTypes": ["devDependencies"], "matchPackageNames": ["eslint", "prettier", "vitest"], "automerge": true } ]}Automerge of all non-major updates:
{ "packageRules": [ { "description": "Automerge non-major excluding v0.x", "matchUpdateTypes": ["minor", "patch"], "matchCurrentVersion": "!/^0/", "automerge": true } ]}Automerge of lock file maintenance:
{ "lockFileMaintenance": { "enabled": true, "automerge": true, "schedule": ["* * * * 0"] }}Branch automerge vs PR automerge
By default, Renovate creates a PR and then merges it through the platform
(platformAutomerge). You can configure a quieter mode with automergeType: "branch": Renovate only creates a branch, and if the tests pass, it pushes the commit directly to the target branch without creating a PR. If the tests fail, it then creates a PR so that you can
investigate.
{ "automergeType": "branch"}Dependency Dashboard
The Dependency Dashboard is an issue that Renovate creates in your repository. It serves as a centralized dashboard showing the state of all the updates: in progress, pending, closed or ignored.
The config:recommended preset enables the Dashboard by default. If you want to
enable it manually:
{ "dependencyDashboard": true}The Dashboard provides three features that are particularly useful in a team context.
Visibility of ignored updates. If someone closes a Renovate PR without merging it, the update appears in the "Closed/Ignored" section of the Dashboard. You can relaunch it with one click by ticking the matching checkbox.
Approval workflow. For sensitive updates, you can ask Renovate to wait for an explicit approval before creating the PR. This approval is given by ticking a checkbox in the Dashboard:
{ "major": { "dependencyDashboardApproval": true }}With this configuration, major updates appear only in the Dashboard. Renovate only creates the PR when you tick the matching checkbox. Minor and patch updates continue as usual.
Abandonment detection. The config:best-practices preset includes
abandonments:recommended, which flags packages that have not published any
update for more than a year. These warnings appear at the top of the Dashboard
to alert you to potentially abandoned dependencies.
Advanced configuration
The packageRules
The packageRules are the central mechanism to customize Renovate's behavior per dependency, group of dependencies, update type or any other criterion. Each rule is an object with matchers (selection criteria) and options to apply.
The main matchers:
| Matcher | Role | Example |
|---|---|---|
matchPackageNames | Package name (glob or regex) | ["react", "@types/**"] |
matchDepTypes | Dependency type | ["devDependencies"] |
matchUpdateTypes | Update type | ["major", "minor", "patch"] |
matchDatasources | Data source | ["docker", "npm"] |
matchFileNames | Source file | ["docker-compose*.yml"] |
matchManagers | Package manager | ["dockerfile", "helm-values"] |
matchCurrentVersion | Current version (regex) | "!/^0/" |
Here is a complete example combining several rules:
{ "extends": ["config:recommended"], "packageRules": [ { "description": "Group the React packages", "matchPackageNames": ["react", "react-dom", "@types/react"], "groupName": "react monorepo" }, { "description": "Automerge lint tools", "matchPackageNames": ["eslint*", "prettier"], "matchUpdateTypes": ["minor", "patch"], "automerge": true }, { "description": "Block Node.js 22+ updates", "matchPackageNames": ["node"], "matchUpdateTypes": ["major"], "enabled": false }, { "description": "Limit Terraform providers to the weekend", "matchManagers": ["terraform"], "matchDatasources": ["terraform-provider"], "schedule": ["* * * * 0,6"] } ]}The rules are evaluated in order: the last rule that matches a dependency takes priority for each option it defines.
Custom Managers
The customManagers let Renovate detect dependencies in files with a
non-standard format. Renovate supports two types of custom managers: regex and jsonata.
The regex type is the most common. You write a
regular expression (in French) that captures the
necessary information: depName, currentValue, and datasource.
Let us take a concrete example: you have a shell script that downloads an Ubuntu cloud image, and you want Renovate to detect and update the version automatically.
In your download-ubuntu.sh script:
# renovate: datasource=github-releases depName=canonical/cloud-initCLOUD_INIT_VERSION="24.4"In renovate.json:
{ "customManagers": [ { "customType": "regex", "managerFilePatterns": ["/\\.sh$/"], "matchStrings": [ "#\\s*renovate:\\s*datasource=(?<datasource>.*?)\\s+depName=(?<depName>.*?)\\n.*?VERSION=\"(?<currentValue>.*?)\"" ] } ]}The structured comment # renovate: datasource=... depName=... in the source file provides the context the regex needs. This convention makes any file "renovatable" without changing its format.
The pattern reads in three parts: the comment (#\s*renovate:\s*datasource=, where \s* accepts spaces), the values captured by named groups ((?<datasource>.*?) and (?<depName>.*?), where .*? takes as few characters as possible), then, on the next line, VERSION="...", whose content becomes currentValue. In the JSON, each backslash is doubled (\\s for \s), because the backslash is already the escape character of JSON. The basic syntax is the one from the lesson Regular expressions in Python (in French), with one difference: a group name is written here (?<name>...), there (?P<name>...).
The managerFilePatterns field lists the files to analyze. A regular expression is written there between slashes ("/\\.sh$/"); without them, the value is read as a glob ("**/*.sh"). It replaces fileMatch: managerFilePatterns is available from 40.2.0 (May 2025), fileMatch has no longer been a documented option since Renovate 41.0.0, and an old configuration is migrated automatically. The datasource can also come from a datasourceTemplate field instead of the comment.
Custom Datasources
When the versions of a tool are not published on a classic registry (npm, PyPI, Docker Hub...), you can create a customDatasource that queries a custom URL:
{ "customDatasources": { "UbuntuCloudImages": { "defaultRegistryUrlTemplate": "https://cloud-images.ubuntu.com/releases/24.04/", "format": "html" } }, "packageRules": [ { "matchDatasources": ["custom.UbuntuCloudImages"], "extractVersion": "^release-(?<version>\\d+)/$" } ]}The supported formats are json, plain, html and yaml. The extractVersion field uses a regex to extract the version number from the returned content.
Grouping updates
By default, Renovate creates a separate PR per dependency. On a large project, this can generate dozens of PRs. Grouping (groupName) gathers
several dependencies into a single PR:
{ "packageRules": [ { "description": "Group all AWS SDK dependencies", "matchPackageNames": ["@aws-sdk/**"], "groupName": "AWS SDK" }, { "description": "Group all non-major updates into one PR", "matchUpdateTypes": ["minor", "patch"], "groupName": "all non-major dependencies", "groupSlug": "all-minor-patch" } ]}The group:allNonMajor preset does exactly this, concisely:
{ "extends": ["config:recommended", "group:allNonMajor"]}Limiting the number of PRs
To avoid overload, Renovate offers several limiters:
| Option | Role | Default value |
|---|---|---|
prConcurrentLimit | Max number of PRs open in parallel | 10 |
prHourlyLimit | Max number of PRs created per hour | 2 |
branchConcurrentLimit | Max number of active branches | 10 |
{ "prConcurrentLimit": 5, "prHourlyLimit": 1}Securing Renovate
Renovate runs code coming from your repositories (install scripts, post- upgrade tasks). On a self-hosted installation shared between several teams, a bad configuration can turn Renovate into a supply chain attack vector. This section details the risks and the countermeasures.
Risk 1, Autodiscovery without a filter
When autodiscover: true is enabled without restriction, Renovate will process all the repositories the bot has access to. On GitLab, an attacker can invite the bot into a booby-trapped repository (on GitLab, accepting an invitation is automatic),
and on the next run, Renovate clones the malicious repository and runs its
scripts.
For example, a booby-trapped Gradle repository with a modified gradlew will run arbitrary code during the dependency resolution phase, because Renovate invokes
the language's native manager.
Countermeasure: always restrict autodiscovery with an explicit filter:
{ "autodiscover": true, "autodiscoverFilter": ["my-org/frontend-*", "my-org/backend-*"]}Or better, use a fixed list of repositories in your self-hosted global configuration:
{ "repositories": ["my-org/web-app", "my-org/backend-api"]}Risk 2, Install scripts and environment variables
Two self-hosted options are particularly dangerous if they are badly configured:
allowScripts: truelets repositories run thepostinstall,prepare, etc. scripts duringnpm install. A malicious package can place arbitrary code there.exposeAllEnv: truepasses all the environment variables of the Renovate process on to the subprocesses. TheRENOVATE_TOKENtoken can be exfiltrated through a crafted commit message.
Countermeasure: keep the default values and explicitly configure what you need:
{ "allowScripts": false, "exposeAllEnv": false, "ignoreScripts": true, "allowedCommands": []}If you need a specific post-upgrade script, restrict it with
a strict regex in allowedCommands:
{ "allowedCommands": ["^npm run lint:fix$", "^go mod tidy$"]}Risk 3, Automerge without a security delay
If automerge is enabled without a cooldown period, a compromised npm package can be published and merged into your project within minutes, before anyone detects the problem. This is called the golden hour of the supply chain attack.
Countermeasure: enable minimumReleaseAge to impose a delay between the
publication of a version and its adoption by Renovate:
{ "extends": ["config:best-practices"], "minimumReleaseAge": "3 days"}The config:best-practices preset already includes a minimumReleaseAge of 3 days
for the npm ecosystem. You can adjust it per dependency through the
packageRules.
Risk 4, Race condition on automerge (GitLab)
On GitLab, a malicious developer with a developer role can add a commit to the branch of a Renovate MR before the bot enables
automerge. If the timing is right, the unreviewed commit is automatically merged into the protected branch, bypassing the four-eyes review principle.
Countermeasure: configure GitLab to allow automerge only if the CI pipeline has been rerun after the last commit:
- Enable pipelines for merge results
- Require that all the pipeline jobs have passed on the last commit
Complete hardened self-hosted configuration
For a secure self-hosted installation, combine all the countermeasures
in your global configuration (a config.js file or environment
variables):
// config.js - hardened self-hosted global configurationmodule.exports = { platform: 'gitlab', endpoint: 'https://gitlab.example.com/api/v4', token: process.env.RENOVATE_TOKEN,
// Restrict the repositories processed autodiscover: true, autodiscoverFilter: ['my-org/frontend-*', 'my-org/backend-*'],
// Block the execution of arbitrary code allowScripts: false, exposeAllEnv: false, allowedCommands: ['^npm run lint:fix$'],
// Security delay extends: ['config:best-practices'],
// Audit the actions repositoryCache: 'enabled',};Running Renovate in CI/CD
In production, Renovate is rarely launched by hand. It is integrated into a CI/CD pipeline that runs it at regular intervals (typically every hour or every night).
Use the official action renovatebot/github-action:
name: Renovateon: schedule: - cron: '0 */2 * * *' # Every 2 hours workflow_dispatch:permissions: {}jobs: renovate: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - uses: renovatebot/github-action@3064367f740a1a91cca218698a63902689cce200 # v46.1.20 with: configurationFile: renovate.json token: ${{ secrets.RENOVATE_TOKEN }} env: RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}Add a scheduled job to your .gitlab-ci.yml:
renovate: image: renovate/renovate:43.278.5@sha256:20583613f720a22e2a68be7bc94aad856ab37dfeca654d901938e51ab021f371 stage: maintenance variables: RENOVATE_TOKEN: $RENOVATE_TOKEN RENOVATE_GITHUB_COM_TOKEN: $RENOVATE_GITHUB_COM_TOKEN RENOVATE_PLATFORM: gitlab RENOVATE_ENDPOINT: $CI_API_V4_URL LOG_LEVEL: info script: - renovate $CI_PROJECT_PATH rules: - if: $CI_PIPELINE_SOURCE == "schedule"Then create a schedule in the GitLab CI/CD settings to trigger this pipeline every hour or as needed.
Troubleshooting
| Symptom | Likely cause | Solution |
|---|---|---|
| Renovate creates no PR | Repository not yet onboarded | Merge the onboarding PR, or check that renovate.json exists |
| Automerge does not work | Protected branch with mandatory reviews | Set platformAutomerge: true and add the bot as an authorized author |
| "Automerge: Disabled by config" in the PR | Incorrect automerge configuration | Check the packageRules: the last matching rule takes priority |
| PRs created then closed immediately | Rate limit reached or lock file in conflict | Check the logs with LOG_LEVEL=debug, check prConcurrentLimit |
| Lock file not updated | Package manager not found | In self-hosted, check binarySource and that the tools are installed |
| Dependency Dashboard not created | Feature not supported by the platform | The Dashboard requires Markdown issues (not supported on Bitbucket Server) |
| "Cannot find manager" in the logs | File format not recognized | Check the file name or create a customManager |
A customManager detects nothing | Pattern refused by RE2 (lookaround assertion, backreference) or managerFilePatterns without slashes read as a glob | Remove (?=...), (?<=...) and \1 from the pattern; write "/\\.sh$/" for a regex |
| Too many PRs | No schedule or limit configured | Add schedule, prConcurrentLimit and consider group:allNonMajor |
Key takeaways
- Renovate automates the creation of PRs to update your dependencies, covering a very large number of package managers.
- Presets (
config:recommended,config:best-practices) offer a solid base without complex manual configuration. - Automerge reduces the workload for low-risk updates (patches, devDependencies, lock files), but always require passing CI tests.
- The Dependency Dashboard centralizes visibility on all the updates and allows an approval workflow for sensitive changes.
minimumReleaseAgeis a first protection against supply chain attacks: impose a delay before adopting a new version.- In self-hosted mode, never enable
autodiscoverwithout a filter, norallowScriptsorexposeAllEnvwithout an explicit reason. - The packageRules allow granular control: group, schedule, automerge or block per dependency, manager or update type.
- The customManagers detect versions in non-standard files:
files are declared with
managerFilePatterns(regex between/…/, otherwise glob), and patterns run with RE2, without lookaround assertions or backreferences.