Automate Dependency Updates with Renovate
Configure Renovate to group non-major updates, pin GitHub Actions to commit SHAs, require passing CI, and cap the number of concurrent pull requests.
Task
Add a Renovate configuration that groups safe dependency updates, pins GitHub Actions by digest, and caps concurrent pull requests.
When to use this
Dependencies and GitHub Actions drift for months because manual update pull requests are noisy, and security patches sit unreviewed.
Prerequisites
- A GitHub repository with Actions enabled and branch protection on the default branch
- The Renovate GitHub app installed on the repository or a self-hosted Renovate runner
- GitHub CLI authenticated for the verification commands
- A committed lockfile so Renovate can update the resolved dependency graph
Steps
1. Add a repository-level Renovate configuration with grouped updates, digest pinning, a weekly schedule, and conservative concurrency limits.
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended", ":dependencyDashboard", ":semanticCommits"],
"timezone": "UTC",
"schedule": ["before 6am on Monday"],
"prConcurrentLimit": 4,
"prHourlyLimit": 2,
"rangeStrategy": "bump",
"packageRules": [
{
"description": "Group non-major dev dependency updates",
"matchDepTypes": ["devDependencies"],
"matchUpdateTypes": ["minor", "patch"],
"groupName": "dev dependencies (non-major)"
},
{
"description": "Automerge patch updates for established packages after CI",
"matchUpdateTypes": ["patch"],
"matchCurrentVersion": ">=1.0.0",
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
},
{
"description": "Pin GitHub Actions to commit SHAs",
"matchManagers": ["github-actions"],
"pinDigests": true
},
{
"description": "Require dashboard approval for major updates",
"matchUpdateTypes": ["major"],
"dependencyDashboardApproval": true
}
],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"]
},
"osvVulnerabilityAlerts": true
}
Expected output: renovate.json exists at the repository root with a valid schema URL, four package rules, and a dependency dashboard preset.
2. Validate the configuration with the validator shipped in the Renovate package before opening a pull request.
npx --yes --package renovate renovate-config-validator renovate.jsonExpected output: The validator prints Validating renovate.json followed by Config validated successfully and exits 0.
3. Commit the configuration on a branch and open a pull request against the protected default branch.
git checkout -b chore/renovate
git add renovate.json
git commit -m "chore: add renovate configuration"
git push -u origin chore/renovate
gh pr create \
--title "chore: add renovate configuration" \
--body "Enables grouped dependency updates, GitHub Actions SHA pinning, and CI-gated automerge." \
--base "$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')"
Expected output: The branch is pushed, a pull request is created, and the required CI checks start against the new configuration.
4. After merging, confirm that Renovate created the Dependency Dashboard issue and is discovering dependencies.
gh issue list --search "Dependency Dashboard in:title" \
--json number,title,state --limit 1
Expected output: One open issue titled Dependency Dashboard is returned, and its body lists pending updates and major-version approvals.
5. Inspect the first update pull requests, confirm that non-major dev updates are grouped, and check that an Actions update is pinned to a full SHA.
gh pr list --label dependencies \
--json number,title,headRefName,isDraft --limit 10
pr=$(gh pr list --search "actions/checkout" --json number --jq '.[0].number')
gh pr diff "$pr" | grep 'uses: actions/checkout@'
Expected output: The PR list shows a grouped dev-dependencies update, while major updates appear on the dashboard as approval items rather than open PRs; the checkout diff shows a 40-character commit SHA instead of a mutable tag.
6. Inspect every open dependency pull request and confirm that at least one automerge candidate has native auto-merge enabled and all checks successful.
gh pr list --label dependencies --json number --jq '.[].number' | while read -r pr; do
gh pr view "$pr" \
--json number,title,autoMergeRequest,statusCheckRollup \
--jq '{number, title, autoMerge: (.autoMergeRequest != null), checks: [.statusCheckRollup[]?.conclusion]}'
done
Expected output: At least one PR reports autoMerge true and a checks array containing SUCCESS; PRs waiting on checks report an empty or pending conclusion and do not merge.
Troubleshooting
Problem
Renovate never opens an onboarding pull request
Solution
Confirm the Renovate app is installed on this repository and has permission to read metadata and write pull requests. Check the app dashboard for a configuration error.
Problem
The repository receives too many pull requests
Solution
Lower prConcurrentLimit and prHourlyLimit, add groupName rules for related packages, and move minor updates to a weekly schedule.
Problem
Automerge is enabled but the pull request stays open
Solution
Branch protection is waiting on a required check, the native auto-merge feature is disabled for the repository, or the app lacks write permission. Read the PR checks and merge state.
Problem
GitHub Actions remain on mutable tags
Solution
pinDigests only applies to the github-actions manager. Verify matchManagers, and ensure workflows reference remote actions rather than local composite actions.
Limitations
- Automerge is only as safe as the test suite; a patch release can still break behavior that CI does not cover.
- Private registries and authenticated package hosts need hostRules credentials, which this configuration does not include.
- Schedules use UTC and a hosted runner may process the queue after the nominal window.
Reduce noise before increasing automation
Dependency automation fails when it creates more work than it removes. A repository that receives twenty individual pull requests every Monday will either ignore them or merge them without reading. Start with grouping: all non-major dev dependencies can share one PR because they are usually tested together and rarely affect production runtime. Runtime dependencies deserve separate groups by ecosystem or criticality, not one giant PR that mixes a linter with a database driver.
Concurrency limits are part of the design. prConcurrentLimit caps the open PRs Renovate will maintain, and prHourlyLimit prevents a burst after a long pause. A weekly schedule gives the team a predictable review window. Vulnerability alerts are the exception: a security fix should not wait for Monday, which is why vulnerabilityAlerts remains enabled outside the normal cadence.
Pin actions, gate automerge
GitHub Actions referenced by a tag are mutable; a compromised or retagged release can change what runs in CI. pinDigests rewrites uses: owner/action@v4 to a full commit SHA and lets Renovate update the digest when a new release appears. This is supply-chain hygiene, not a guarantee that the action is safe, so still review major action upgrades.
Automerge should be limited to changes with a strong safety net. Patch updates for packages already at 1.0 or later are a reasonable starting point when the test suite is meaningful. Major updates require dashboard approval, which keeps them out of the PR queue until a human decides to spend the migration effort. Native auto-merge (platformAutomerge) waits for branch protection checks; Renovate’s own merge is a fallback if native auto-merge is unavailable.
Read the dashboard
The Dependency Dashboard is the control panel, not a notification. It lists detected dependencies, pending updates, ignored items, and major versions awaiting approval. If a package is missing, the manager did not detect it; check the file pattern and the lockfile. If an update is repeatedly failing, the dashboard shows the PR and the error. Use the dashboard to approve a major update deliberately, then let the normal PR review process take over.
Verify the first cycle
Validation catches schema errors before the app runs. After merge, wait for the first scheduled run and inspect the PR list. A grouped dev-dependency PR should contain multiple packages; a major update should appear on the dashboard but not as an open PR. For an Actions update, inspect the diff and confirm the uses line ends in a 40-character SHA. Before merging an automerge candidate, check that the required checks are green and that native auto-merge is actually enabled.
Pitfalls
Do not enable automerge for major versions or for packages without tests. Do not pin actions by tag and assume Renovate will fix it; the manager must see the workflow files. Do not put registry credentials in renovate.json; use the app’s secret storage or hostRules with environment-injected values. And do not let the dependency dashboard become the only place someone looks; route failed security PRs to the same channel as other incidents.
Example
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended", ":dependencyDashboard", ":semanticCommits"],
"timezone": "UTC",
"schedule": ["before 6am on Monday"],
"prConcurrentLimit": 4,
"prHourlyLimit": 2,
"rangeStrategy": "bump",
"packageRules": [
{
"description": "Group non-major dev dependency updates",
"matchDepTypes": ["devDependencies"],
"matchUpdateTypes": ["minor", "patch"],
"groupName": "dev dependencies (non-major)"
},
{
"description": "Automerge patch updates for established packages after CI",
"matchUpdateTypes": ["patch"],
"matchCurrentVersion": ">=1.0.0",
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
},
{
"description": "Pin GitHub Actions to commit SHAs",
"matchManagers": ["github-actions"],
"pinDigests": true
},
{
"description": "Require dashboard approval for major updates",
"matchUpdateTypes": ["major"],
"dependencyDashboardApproval": true
}
],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"]
},
"osvVulnerabilityAlerts": true
}