Outdated dependencies are a security liability and a technical debt accumulation point. Renovate automates dependency updates by opening PRs, grouping related updates, and auto-merging safe patches — so remote teams get current without drowning in manual update work.
Table of Contents
- Prerequisites
- Dependency Dashboard and Visibility
- Stabilization Period and Release Age
- Ignoring and Pinning Specific Packages
- Debugging and Testing Renovate Config
- Renovate with GitLab CI
- Using Presets for Cross-Repo Consistency
- Measuring Renovate’s Impact
- Related Reading
Prerequisites
Before you begin, make sure you have the following ready:
- A computer running macOS, Linux, or Windows
- Terminal or command-line access
- Administrator or sudo privileges (for system-level changes)
- A stable internet connection for downloading tools
Step 1: Install ation Options
Option 1: GitHub App (Easiest)
# 1. Install the Mend Renovate app from GitHub Marketplace
# 2. Grant access to your repositories
# 3. Add renovate.json to your repo root
Option 2: Self-Hosted with GitHub Actions
# .github/workflows/renovate.yml
name: Renovate
on:
schedule:
- cron: '0 4 * * 1-5' # Weekdays at 4am
workflow_dispatch:
jobs:
renovate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: renovatebot/github-action@v40
with:
configurationFile: renovate.json
token: ${{ secrets.RENOVATE_TOKEN }}
env:
LOG_LEVEL: debug
Option 3: Self-Hosted CLI
# Install
npm install -g renovate
# Run against a repo
RENOVATE_TOKEN=your-github-token \
RENOVATE_PLATFORM=github \
renovate yourorg/yourrepo
Step 2: Base Configuration
// renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
":disableDependencyDashboard"
],
"timezone": "America/New_York",
"schedule": ["before 6am on Monday"],
"prConcurrentLimit": 5,
"prHourlyLimit": 2,
"commitMessagePrefix": "chore(deps):",
"labels": ["dependencies"],
"assignees": ["@yourteam/backend"],
"reviewers": ["@yourteam/leads"]
}
Step 3: Grouping Updates
Reduce PR noise by grouping related packages:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base"],
"packageRules": [
{
"groupName": "AWS SDK",
"matchPackagePatterns": ["^@aws-sdk/", "^aws-sdk"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "React core",
"matchPackageNames": ["react", "react-dom", "@types/react", "@types/react-dom"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "ESLint and plugins",
"matchPackagePatterns": ["^eslint", "^@typescript-eslint/"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "Testing libraries",
"matchPackagePatterns": ["^jest", "^@testing-library/", "^vitest"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "Storybook",
"matchPackagePatterns": ["^@storybook/", "^storybook"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "Development tools",
"matchDepTypes": ["devDependencies"],
"matchUpdateTypes": ["patch"],
"automerge": true
}
]
}
Step 4: Auto-Merge Safe Updates
{
"packageRules": [
{
"description": "Auto-merge patch updates for trusted packages",
"matchPackagePatterns": ["^@types/"],
"matchUpdateTypes": ["patch"],
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
},
{
"description": "Auto-merge patch updates for dev dependencies",
"matchDepTypes": ["devDependencies"],
"matchUpdateTypes": ["patch"],
"automerge": true,
"automergeType": "pr"
},
{
"description": "Never auto-merge major updates",
"matchUpdateTypes": ["major"],
"automerge": false,
"dependencyDashboard": true
},
{
"description": "Pin Docker digest updates (auto-merge)",
"matchDatasources": ["docker"],
"matchUpdateTypes": ["digest"],
"automerge": true
}
]
}
Step 5: Python / Poetry Configuration
{
"extends": ["config:base"],
"pip_requirements": {
"fileMatch": ["requirements.*\\.txt$"]
},
"poetry": {
"fileMatch": ["pyproject\\.toml$"]
},
"packageRules": [
{
"matchManagers": ["poetry"],
"matchDepTypes": ["dev-dependencies"],
"matchUpdateTypes": ["patch"],
"automerge": true
},
{
"matchManagers": ["poetry"],
"matchDepTypes": ["dependencies"],
"matchUpdateTypes": ["major"],
"labels": ["major-update", "review-required"]
}
]
}
Step 6: Docker and GitHub Actions Updates
{
"extends": ["config:base"],
"docker-compose": {
"fileMatch": ["docker-compose.*\\.yml$"]
},
"dockerfile": {
"fileMatch": ["(^|/)Dockerfile[^/]*$"]
},
"github-actions": {
"fileMatch": ["\\.github/workflows/.*\\.yml$"]
},
"packageRules": [
{
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true,
"automergeType": "pr"
},
{
"matchManagers": ["dockerfile"],
"matchUpdateTypes": ["patch"],
"automerge": false
},
{
"description": "Pin Docker base image digests",
"matchManagers": ["dockerfile"],
"pinDigests": true
}
]
}
Step 7: Security-Only Mode
For repos where you only want to act on known vulnerabilities:
{
"extends": ["config:base", ":onlyNpmDependencies"],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"],
"assignees": ["@yourteam/security"],
"automerge": false,
"minimumReleaseAge": "0 days"
},
"osvVulnerabilityAlerts": true,
"packageRules": [
{
"matchUpdateTypes": ["major", "minor", "patch"],
"enabled": false
},
{
"matchCategories": ["security"],
"enabled": true
}
]
}
Step 8: Monorepo Configuration
{
"extends": ["config:base"],
"ignorePaths": [
"**/node_modules/**",
"**/vendor/**"
],
"packageRules": [
{
"matchPaths": ["services/api/**"],
"groupName": "api-dependencies",
"schedule": ["before 6am on Tuesday"],
"assignees": ["@yourteam/backend"]
},
{
"matchPaths": ["services/web/**"],
"groupName": "web-dependencies",
"schedule": ["before 6am on Wednesday"],
"assignees": ["@yourteam/frontend"]
},
{
"matchPaths": ["infrastructure/**"],
"matchManagers": ["terraform"],
"groupName": "terraform-providers",
"schedule": ["before 6am on Thursday"],
"assignees": ["@yourteam/platform"]
}
]
}
Step 9: PR Description Customization
{
"prBodyTemplate": "This PR contains the following updates:\n\n{{{table}}}\n\n{{{notes}}}\n\n{{{changelogs}}}\n\n---\n\n**Merge checklist:**\n- [ ] CI passes\n- [ ] No breaking changes in changelog\n- [ ] Tested in staging if applicable",
"commitBody": "Renovate automated update — review the changelog above"
}
Step 10: Run Renovate on Gitea
{
"platform": "gitea",
"endpoint": "https://git.example.com",
"token": "your-gitea-token",
"repositories": [
"mycompany/api",
"mycompany/web",
"mycompany/infrastructure"
]
}
RENOVATE_PLATFORM=gitea \
RENOVATE_ENDPOINT=https://git.example.com \
RENOVATE_TOKEN=your-token \
renovate mycompany/api
Dependency Dashboard and Visibility
The Dependency Dashboard is a GitHub issue Renovate keeps updated with a full picture of pending and blocked updates across your repo. Enable it selectively:
{
"dependencyDashboard": true,
"dependencyDashboardTitle": "Renovate Dependency Dashboard",
"dependencyDashboardHeader": "This dashboard lists all pending, blocked, and rate-limited updates.",
"dependencyDashboardAutoclose": true,
"packageRules": [
{
"matchUpdateTypes": ["major"],
"dependencyDashboard": true,
"dependencyDashboardApproval": true
}
]
}
With dependencyDashboardApproval: true, Renovate will only open a PR for a major update after a team member checks the corresponding checkbox in the dashboard issue. This gives you a lightweight approval gate without a full review workflow.
Stabilization Period and Release Age
Avoid being the first team to hit a broken release by requiring packages to age before Renovate acts on them:
{
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"minimumReleaseAge": "3 days",
"internalChecksFilter": "strict"
},
{
"matchDepTypes": ["devDependencies"],
"minimumReleaseAge": "1 day"
},
{
"matchUpdateTypes": ["major"],
"minimumReleaseAge": "7 days"
}
]
}
The internalChecksFilter: "strict" setting tells Renovate to wait for its own internal age check to pass before opening the PR, even if the package satisfies other rules. Three days is a reasonable default that filters out yanked or immediately hotfixed releases without adding meaningful delay.
Ignoring and Pinning Specific Packages
Some packages need to stay pinned due to compatibility constraints or pending migration work:
{
"packageRules": [
{
"matchPackageNames": ["webpack", "webpack-cli"],
"enabled": false,
"description": "Pinned at v4 until webpack 5 migration completes"
},
{
"matchPackageNames": ["typescript"],
"allowedVersions": "<5.4.0",
"description": "Block TS 5.4 until tsconfig audit done"
},
{
"matchPackagePatterns": ["^@internal/"],
"enabled": false,
"description": "Internal packages managed manually via changesets"
}
]
}
You can also pin the current version of a package from the Dependency Dashboard by checking its pin checkbox — Renovate will add a // renovate: pinned comment to package.json and stop proposing updates for it.
Debugging and Testing Renovate Config
Before deploying to a live repo, validate your configuration locally:
# Validate renovate.json schema
npm install -g renovate
renovate-config-validator renovate.json
# Dry run against a repository (no PRs created)
LOG_LEVEL=debug \
RENOVATE_TOKEN=your-github-token \
renovate --dry-run=lookup yourorg/yourrepo 2>&1 | tee renovate-dry-run.log
# Check which packages would be updated
grep "packageName\|newVersion\|currentVersion" renovate-dry-run.log | head -40
The dry-run output shows every package Renovate evaluated, which update it would propose, and why it was skipped (version constraint, minimum release age, disabled rule, etc.). Run this before pushing config changes to catch misconfigured package rules.
Renovate with GitLab CI
Self-hosted Renovate on GitLab uses a pipeline schedule rather than GitHub Actions:
# .gitlab-ci.yml
renovate:
image: renovate/renovate:latest
stage: maintenance
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
variables:
RENOVATE_TOKEN: $RENOVATE_GITLAB_TOKEN
RENOVATE_PLATFORM: gitlab
RENOVATE_ENDPOINT: https://gitlab.example.com/api/v4
LOG_LEVEL: info
script:
- renovate yourgroup/yourrepo
Create a GitLab CI/CD schedule that runs this pipeline daily at 5 AM. Store the Renovate token — a GitLab personal access token with api scope — as a masked CI/CD variable named RENOVATE_GITLAB_TOKEN.
Using Presets for Cross-Repo Consistency
When you manage more than a handful of repositories, maintaining identical Renovate config in each one becomes a drift problem. Renovate presets solve this: define a shared config in one repo and extend it everywhere else.
Create a renovate-config repo at yourorg/renovate-config with a default.json:
// default.json in yourorg/renovate-config
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"description": "ACME organization default Renovate config",
"extends": ["config:base"],
"timezone": "America/New_York",
"schedule": ["before 6am on Monday"],
"prConcurrentLimit": 5,
"prHourlyLimit": 2,
"commitMessagePrefix": "chore(deps):",
"labels": ["dependencies"],
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"matchDepTypes": ["devDependencies"],
"automerge": true
},
{
"matchUpdateTypes": ["major"],
"dependencyDashboard": true,
"dependencyDashboardApproval": true
}
]
}
Each project repo reduces its renovate.json to a single line:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>yourorg/renovate-config"]
}
When you adjust the global schedule or add a new group rule, update default.json once and all repos pick it up on their next Renovate run. Projects needing overrides extend the base and add their own packageRules — Renovate merges them in order.
Measuring Renovate’s Impact
After a few weeks, verify Renovate is working as intended by querying GitHub for merged dependency PRs:
# Count merged Renovate PRs in the last 30 days
gh pr list \
--repo yourorg/yourrepo \
--state merged \
--label dependencies \
--json number,title,mergedAt \
--jq 'length'
# List major updates that required approval
gh pr list \
--repo yourorg/yourrepo \
--state merged \
--label dependencies \
--search "major in:title" \
--json number,title,mergedAt \
| jq '.[] | {number, title, mergedAt}'
A healthy Renovate setup for a mid-sized JS project typically generates 5-15 merged PRs per week, with patch auto-merges happening continuously and minor/major updates batched to Monday morning. If you see zero PRs, check the Dependency Dashboard for token errors. If you see hundreds of open PRs, tighten your prConcurrentLimit and add more grouping rules.
Related Reading
- How to Automate Code Quality Gates for Remote Teams
- How to Set Up Verdaccio Private npm Registry
- Best DevsSecOps Toolchain for Remote Teams
- How to Automate Docker Container Updates
Related Articles
- Best Tools for Remote Team Dependency Tracking
- Remote DevOps Team Dependency Update Workflow for
- Best Remote Collaboration Tool for Technical Architects
- How to Write Async Status Updates That Managers Actually
- How to Manage Multiple GitHub Accounts for Remote Work Built by theluckystrike — More at zovo.one