Dependabot and Renovate: real-world lessons and examples. Keep dependencies updated automatically.
After 78 days of building Git and GitHub proficiency, you've mastered branching, code review, and CI/CD pipelines. Now comes the reality check: keeping your dependencies fresh without drowning in pull requests or shipping broken code. Dependabot and Renovate solve this exact problem, and we'll show you how to configure them so they work for your team, not against it.
Automated update pull requests
Both Dependabot (GitHub native) and Renovate (multi-platform) scan your dependency files daily or on a schedule you define. When a new version is available, they create a pull request automatically. This sounds simple, but the real win is that you're no longer manually tracking which packages have updates.
In production systems we've worked on, we discovered that without automation, teams often skip security patches entirely—not maliciously, but because tracking releases across 50+ packages is exhausting. A financial SaaS platform we supported had a critical vulnerability in a transitive dependency that went unpatched for six months simply because no one had visibility into it.
To enable Dependabot on GitHub, create a .github/dependabot.yml file in your repository:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "03:00"
- package-ecosystem: "pip"
directory: "/backend"
schedule:
interval: "weekly"
Renovate, by contrast, offers more granular control and works across GitHub, GitLab, Bitbucket, and Gitea. A sample renovate.json:
{
"extends": ["config:base"],
"schedule": ["before 3am on Monday"],
"timezone": "UTC",
"semanticCommits": true
}
The key decision here: do you want one PR per dependency or grouped PRs? That depends on your team's bandwidth and risk tolerance, which leads us to our next section.
Group minor updates
Without grouping, a repository with 100 dependencies could generate 100 pull requests per week. We've seen teams literally disable dependency tools because the noise was unmanageable. The solution is intelligent grouping.
Dependabot's grouping (beta feature at time of writing) and Renovate's native grouping allow you to bundle related updates. In a NestJS backend with both Express and Fastify adapters, you might group all Express ecosystem updates together, and Fastify ecosystem updates separately.
Here's a Renovate configuration that groups by package type and allows minors/patches to batch together:
{
"extends": ["config:base"],
"groupName": "all non-major",
"groupSlug": "all-minor-patch",
"matchUpdateTypes": ["minor", "patch"],
"semanticCommits": true,
"schedule": ["before 3am on Monday"],
"postUpdateOptions": ["gomodTidy", "npmDedupe"]
}
For major versions, keep them separate—they require more scrutiny:
{
"extends": ["config:base"],
"matchUpdateTypes": ["major"],
"groupName": "major updates (manual review)",
"enabled": true,
"groupSlug": "major-updates"
}
A ride-hailing platform we worked with implemented this two-tier approach: minor/patch updates auto-merged if tests passed, major updates created separate PRs requiring explicit approval. This reduced review fatigue by 60% while maintaining safety.
Auto-merge safe patches with passing tests
This is where dependency tools become truly valuable. If a patch version of a logging library passes your entire test suite, shipping it immediately is both faster and safer than waiting weeks for human review.
Dependabot supports auto-merge when you enable it in repository settings. Renovate supports it natively via configuration. The critical safeguard: auto-merge only if all status checks pass.
Here's how to enable auto-merge in Renovate with protection:
{
"extends": ["config:base"],
"package-rules": [
{
"matchUpdateTypes": ["patch"],
"matchDatasources": ["npm"],
"automerge": true,
"automergeType": "pr",
"requiredStatusChecks": ["test", "lint", "security-scan"]
},
{
"matchUpdateTypes": ["minor"],
"automerge": true,
"automergeMinor": true,
"requiredStatusChecks": ["test", "lint", "security-scan"]
}
]
}
We also recommend enabling branch protection rules that prevent merging without passing checks:
| Setting | Recommended Value | Reasoning |
|---|---|---|
| Require status checks to pass | Yes | Catches breaking changes before merge |
| Require code review approvals | No (for patches) | Patch versions rarely break contracts |
| Require status checks to pass before merging | Yes | Prevents merge of outdated checks |
| Require up-to-date branches | Yes | Reruns tests against main before merge |
An e-commerce team we advised initially set up auto-merge without protecting against failing tests. Within two weeks, a patch update to a JSON parsing library broke production. Since then, they've added branch protection and haven't had a single auto-merge regression in 18 months.
Security updates first
Not all updates are equal. A patch fixing a known CVE needs to ship faster than a minor version adding a new feature. Both Dependabot and Renovate can prioritize security updates.
In Dependabot's YAML, use allow to permit security updates to bypass normal scheduling:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
allow:
- dependency-type: "production"
Better yet, configure separate rules for security patches:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
security-updates-only: true
In Renovate, use versioning strategies and prioritization:
{
"extends": ["config:base"],
"vulnerabilityAlerts": true,
"package-rules": [
{
"matchDatasources": ["npm"],
"matchUpdateTypes": ["patch"],
"groupName": "security fixes",
"schedule": ["at any time"],
"automerge": true,
"requiredStatusChecks": ["test"]
}
]
}
A travel booking platform we supported had a critical Redis client vulnerability. Because they'd configured security-first rules, the patch was in production within 4 hours of release. The same organization's non-security updates typically take 3–5 days for review. That's the right balance.
Common mistakes
- Disabling all updates because of noise: Group intelligently instead. One mega-PR per week beats 50 individual ones.
- Auto-merging major versions without review: Major versions can introduce breaking changes. Always require explicit approval for major updates, even if tests pass.
- Ignoring transitive dependencies: Both tools track transitive dependencies, but some teams only watch direct dependencies. You're vulnerable to indirect supply-chain issues if you do this.
- Running tests only for Node.js but not for Docker builds: A dependency update may pass unit tests but fail in a containerized environment. Test in the environment where code runs.
- Setting auto-merge without branch protection: Always require passing checks. A flaky test that occasionally fails will eventually merge broken code if you don't enforce strict gating.
- Treating security updates like regular updates: They need faster cycles and lower review thresholds. Separate them from routine maintenance.
Key takeaways
- Enable automated dependency scanning on day one; manual tracking doesn't scale beyond a handful of packages.
- Group minor and patch updates together, but keep major versions separate for higher scrutiny.
- Auto-merge only when all status checks pass; branch protection rules are your last line of defense.
- Prioritize security updates with daily checks and fast merge policies, regardless of your regular schedule.
- Choose Dependabot if you're GitHub-native and want simplicity; choose Renovate if you need multi-platform support and granular configuration.
- Invest in comprehensive test coverage; your CI/CD is only as good as your test suite when auto-merging.






Comments
Loading comments…