Delivery Workflows
Renovate for platform engineers: Helm, images, OpenTofu
A practical Renovate Kubernetes guide: keep Helm charts, Argo CD manifests, image tags, OpenTofu providers, and GitHub Actions current without the PR flood.

Most teams automate application dependencies long before they automate the platform around them. The service code gets tidy dependency bumps. Meanwhile the estate underneath it drifts quietly: chart versions pinned in GitOps repos, image tags living in values.yaml, OpenTofu providers frozen in a module nobody wants to touch, GitHub Actions still pointing at whatever looked current six months ago. Renovate is one of the few tools that actually understands that layer — but if you switch it on without shaping it, you get a week of noisy pull requests and nobody learns to trust it.
That trust problem matters more than the tooling choice. A dependency bot that opens forty PRs on Monday and gets muted by Wednesday isn’t reducing risk — it’s generating admin. The useful version is much smaller: a handful of grouped, boring, mergeable updates arriving on a schedule your team can absorb.
Platform drift is not housekeeping
It is tempting to file all of this under housekeeping, but a stale runner image, an unpinned GitHub Action, or a chart version that only moves during an outage has a habit of turning into security or delivery work at the least convenient moment.
The pain is also different from application dependency management. If you are already living with the maintenance cost of first-party charts or keeping OpenTofu / Terraform testable, you already know the pattern: the drift is rarely dramatic right up until it is.
Platform repos are usually full of declarative glue rather than one package manager:
- Argo CD
Applicationmanifests pointing at Helm charts values.yamlfiles carrying image tagsDockerfilebases for internal tooling imagesrequired_providersblocks in*.tfand*.tofu- workflow files pulling third-party GitHub Actions
That mixture is where Renovate earns its keep. It models dependency updates as managers — which files to inspect — plus datasources — where to look for newer versions. The important bit for platform teams is that it already knows the shapes you are likely to have: helm-values, helmv3, argocd, kubernetes, terraform, dockerfile, and github-actions among others. You are not trying to force a JavaScript tool to care about cluster YAML. It already does.
If you are maintaining GitOps repos already, this is the same day-two instinct as keeping Argo CD itself honest. The drift is going to happen. The question is whether you discover it incrementally in review, or all at once when an upgrade turns into a migration.
The gotcha most older tutorials get wrong
There is one Renovate detail worth internalising early because it still burns a lot of time: the kubernetes and argocd managers match nothing by default.
That is deliberate. The Renovate docs are explicit that both managers require your own managerFilePatterns, because there is no shared naming convention for Kubernetes or Argo CD YAML across repositories. If you do not set those patterns, Renovate will happily scan your repo and never touch the files you actually cared about.
That would be annoying enough on its own, but there is a second trap layered on top: many tutorials still show the old fileMatch option, which Renovate has since renamed to managerFilePatterns (existing configs are migrated automatically). The same era of stale examples also tends to use stabilityDays instead of minimumReleaseAge, and config:base instead of config:recommended.
So if your first self-hosted run seems weirdly quiet, do not start by distrusting the bot. Start by distrusting the tutorial.
Start with one quiet configuration
Renovate does not need a heroic config to become useful — it needs a narrow one.
This is a sensible starting point for a platform repo that carries Argo CD, raw Kubernetes YAML, OpenTofu, and GitHub Actions:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended", "helpers:pinGitHubActionDigests"],
"timezone": "Europe/London",
"kubernetes": {
"managerFilePatterns": ["/^clusters/.+\\.ya?ml$/"]
},
"argocd": {
"managerFilePatterns": ["/^argocd/.+\\.ya?ml$/"]
},
"packageRules": [
{
"matchManagers": ["terraform"],
"groupName": "terraform providers",
"schedule": ["* 0-4 * * 1"]
},
{
"matchDatasources": ["docker"],
"matchUpdateTypes": ["minor", "patch", "digest"],
"minimumReleaseAge": "3 days",
"automerge": true
}
]
}
That config passes renovate-config-validator as written — config snippets that have never been run are how blog posts become incident fuel.
A few details are doing most of the work here:
config:recommendedenables the dependency dashboard and a sane set of grouping and replacement presets.helpers:pinGitHubActionDigeststurns action references into pinned SHAs, which matters if you care about supply-chain drift in CI.managerFilePatternsscopes Renovate to the directories you actually mean.minimumReleaseAgegives the rest of the world a few days to discover whether a release is broken before you merge it automatically.
That last one is the difference between “automerge is reckless” and “automerge is just another boring platform control”.
Self-hosted first, and the bootstrap is smaller than people expect
If you want to run Renovate yourself, the official docs cover plain Docker and Kubernetes. The Kubernetes example is a CronJob scheduled at @hourly, with the usual knobs passed as environment variables such as RENOVATE_TOKEN, RENOVATE_PLATFORM, and RENOVATE_AUTODISCOVER.
That is a good fit for platform repos because it matches the shape of the job: scan, open or update PRs, exit, repeat — a periodic sweep, not a long-lived controller.
Mend, who maintain Renovate, also run a hosted app, but the self-hosted path is perfectly ordinary and the documentation treats it that way. The Kubernetes example is a manifest rather than a Helm chart, which tells you something useful about the expected complexity level: this is not meant to be an entire platform in its own right.
One default config for the whole estate
That quiet starting config stops being quiet the moment you paste it into your fifteenth repository. Renovate’s answer is shared presets: keep your defaults in a default.json in a dedicated repo — conventionally named renovate-config — and every other repo’s config collapses to one line:
{
"extends": ["github>your-org/renovate-config"]
}
The merge rules are the useful part. Presets resolve first and the repository’s own config is applied on top, so a repo that genuinely needs a different schedule or an extra manager overrides just that key rather than forking the whole file. The estate default lives in one place; the exceptions stay small, visible, and local to the repo that needs them.
Once a preset drives that many repos, it deserves the same care as any other production config. Run renovate-config-validator --strict in the preset repo’s CI so a typo or a deprecated option fails a pull request check there, instead of quietly changing behaviour across the whole estate.
If you are self-hosting there is a stronger version of the same idea: inheritConfig, which makes Renovate read an org-level config from your renovate-config repo for every repository it processes, no extends opt-in required — with each repo’s own config still merged over the top. Presets are shared defaults; inherited config is policy.
The real craft is reducing the number of decisions
The best Renovate setups remove as many low-value decisions as possible, rather than trying to catch everything.
There are four levers that matter most.
1. Group related updates
Terraform providers are the classic example. Five provider bumps landing as five PRs makes review no safer; it just burns reviewer patience. A groupName on the terraform manager collapses that into one change the team can reason about.
The same logic often applies to internal base images or chart estates where several bumps usually move together.
2. Put updates on a schedule people can live with
Renovate’s cron syntax is worth using properly. The examples in the scheduling docs are straightforward and useful: * 0-4 * * * for work before 05:00, * * * * 0,6 for weekends. If your team reviews platform changes on Monday morning, send Terraform then. If minor image bumps can land overnight behind tests, let them.
This sounds mundane, but it is a trust-building feature. A bot that behaves predictably is easier to merge.
3. Gate majors in the dependency dashboard
The dependency dashboard is one of Renovate’s most useful features, especially in platform repos. Instead of opening everything immediately, it gives you one place to see what is pending. Paired with dependencyDashboardApproval, it lets you hold majors until somebody explicitly opts in.
That is a much better operating model than waking up to a surprise provider major in an already-busy week.
4. Automerge only the changes you can explain
Renovate supports automerge, automergeType, and platformAutomerge. The safe pattern is to automerge only the classes of change whose blast radius you understand.
For most teams that means patch, minor, and digest updates on a subset of managers — and only behind branch protection with required status checks. That caveat is not optional. Automerge without tests is not automation. It is delegation without verification.
Two supply-chain details worth keeping
There are two Renovate behaviours that are especially useful in CI and container-heavy repos.
The first is GitHub Action digest pinning. Renovate can maintain pinned SHAs for Actions while still tracking the human-readable version. That is exactly the shape you want: reviewable intent for humans, immutable references for runners.
The second is Docker’s versioning behaviour. Renovate treats the suffix after the first hyphen as a compatibility marker, which matters for tags like 12.15.0-alpine. If you are on -alpine, Renovate keeps you on -alpine rather than helpfully wandering across to a different base variant. That is a quiet detail, but it is one of the reasons this works better than trying to script the problem yourself.
So when is Renovate better than Dependabot now?
The honest answer is narrower than it used to be.
Dependabot now supports Helm version updates, can update Docker image tags in Kubernetes manifests, and has grouping and cooldown features. If all you need is light GitHub-native dependency maintenance, that may be enough.
Where Renovate still stands out for platform work is the shape of the repositories it understands and the amount of control it gives you once they stop looking like a normal application repo:
- Argo CD awareness, not just generic YAML scanning
- the
helm-valuesmanager for image tags embedded in chart values files - a proper dependency dashboard
- native automerge controls
- regex-based custom managers when some dependency lives in a weird internal file format
- stronger handling for mixed estates where OpenTofu, Kubernetes, charts, Docker, and CI all live together
That is the distinction I would use — not that Dependabot is bad, which is no longer true in the broad way people still repeat, but that platform repos have stranger edges, and Renovate is built for stranger edges.
The boring version is the good version
If you remember one thing from this post, make it this: success is when platform updates are ordinary enough that nobody postpones them. Update volume is the means, not the measure.
That usually means fewer PRs, stricter scoping, a couple of schedules, a dependency dashboard for the scary stuff, and automerge only where your tests are already strong enough to deserve it.
Once you do that, Renovate stops feeling like a bot that pesters the team and starts feeling like a maintenance habit the repo enforces for you. That is a much better place to end up than another heroic quarterly dependency sprint — and a lot less dramatic than discovering, mid-incident, how old your pinned chart actually was.





