Configuring Renovate for Grouped Updates in a Monorepo
Renovate is opening a flood of individual PRs across your monorepo packages, and reviewers have stopped looking. This page shows how to group and schedule updates so the bot stays useful at monorepo scale.
Exact symptoms and error messages
Dozens of near-identical PRs land each week, one per package per dependency:
fix(deps): update dependency eslint to v9.15.0 (packages/ui)
fix(deps): update dependency eslint to v9.15.0 (packages/api)
fix(deps): update dependency eslint to v9.15.0 (packages/web)
... 27 more ...
Root cause analysis
By default Renovate treats each dependency in each package as its own update. In a monorepo where the same dependency is shared across packages, that multiplies into unreviewable noise. The fix is to group shared updates and pin the schedule, which aligns with routing lockfile churn through a few reviewable PRs, per Lockfile Management Strategies.
Monorepos amplify the noise because the same dependency is declared in many packages. Renovate, by default, opens an update per dependency per package, so a single eslint bump can fan out into a dozen near-identical PRs. Reviewers pattern-match that as noise and stop looking, which defeats the entire point of automation — the bumps pile up unreviewed and the repo drifts anyway. Grouping collapses that fan-out back into one intent-bearing change.
Scheduling addresses a second failure mode: a continuous stream of PRs that arrive at random times competes with feature work for attention. Pinning updates to a predictable window turns dependency maintenance into a routine chore rather than a constant interruption, and it keeps CI load — every PR triggers the affected build — bounded and predictable.
Resolution and configuration patch
// renovate.json
{
"extends": ["config:recommended"],
"schedule": ["before 6am on monday"],
"packageRules": [
{ "matchUpdateTypes": ["minor", "patch"], "groupName": "all non-major", "groupSlug": "non-major" },
{ "matchDepTypes": ["devDependencies"], "groupName": "dev dependencies" },
{ "matchUpdateTypes": ["major"], "dependencyDashboardApproval": true }
]
}
CLI validation and debug commands
# Dry-run Renovate locally to preview the PRs it would open
LOG_LEVEL=debug npx renovate --dry-run=full
# Confirm shared deps resolve to one version across the workspace
pnpm why eslint
Prevention and CI guardrails
- Group minor/patch updates into a single scheduled batch.
- Require approval for majors via the dependency dashboard.
- Pin a schedule so PRs arrive predictably instead of continuously.
- Keep shared dev tooling (eslint, tsconfig) in its own group for one-glance review.
Separating security updates from the batch
Grouping routine bumps is right, but security fixes should not wait for Monday's batch. Give vulnerability alerts their own rule so they arrive immediately, labeled and ungrouped, while everything else stays batched. That preserves the reviewable cadence for routine work without delaying the updates that actually matter.
{
"vulnerabilityAlerts": {
"labels": ["security"],
"schedule": ["at any time"],
"groupName": null
}
}
The result is a two-speed pipeline: security fixes on a fast lane with their own PRs, and routine minor/patch updates collected into a predictable weekly batch. Reviewers learn to trust the label, and nothing important is buried in a pile of @types/* bumps.
An automerge policy for low-risk updates
Grouping cuts the count of PRs; automerge cuts the human touch on the ones that are genuinely safe. The key is a policy narrow enough to trust: patch and minor updates to dev dependencies, gated on a green CI run, are the classic candidates. Production dependencies and any major bump stay manual.
{
"packageRules": [
{
"matchDepTypes": ["devDependencies"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
}
]
}
Automerge is only as safe as the test suite behind it, so treat it as a statement of confidence in CI. Start with dev dependencies where a regression is caught by your own build, watch how it behaves for a few weeks, and widen the policy only if the signal stays clean. The goal is to spend human review on the updates that can actually break production, not on a stream of @types/* patches.
Frequently Asked Questions
Does grouping hide which package changed?
No — the grouped PR still updates each affected package's manifest and the lockfile. Grouping changes how many PRs you review, not what is in them.
Can Renovate keep security updates ungrouped?
Yes. Give vulnerabilityAlerts its own rule and label so security fixes arrive as separate, fast-lane PRs while routine bumps stay batched.
Will grouping delay a critical security patch?
Not if you give vulnerabilityAlerts its own rule with an immediate schedule and no group. Routine version bumps stay batched, while security fixes bypass the batch and arrive as separate, labeled PRs the moment they are available.
How do I stop Renovate flooding CI on Monday morning?
Cap prConcurrentLimit and prHourlyLimit so PRs land in a controlled trickle, and keep the batch grouped so it is one PR rather than dozens. That bounds the CI load each update window generates.
Can one Renovate config serve many repos?
Yes — put your rules in a shared preset and extends it from each repo's renovate.json. Repositories inherit the grouping, schedule, and limits, and only override what is genuinely repo-specific.
Related
- Dependency Auditing and Automated Updates — the overview for auditing and update automation.