Skip to content
Go back

Renovate for k8s GitOps

By SumGuy 14 min read
Renovate for k8s GitOps
Contents

You’re Manually Bumping Image Versions in Your GitOps Repo. Stop That.

If you’re running Kubernetes the right way, manifests in Git, ArgoCD or Flux syncing them to the cluster, you’ve probably noticed something annoying: new container image releases drop constantly, chart maintainers push updates, and somebody has to go hand-edit those YAML files and commit the changes. That somebody is usually you at 2 AM, wondering if you missed a tag somewhere.

Renovate fixes this. It’s a bot that watches your dependencies (images, charts, base images in Dockerfiles, whatever) and opens PRs when updates are available. You review, test, merge. Automation handles the tedious parts. It’s like hiring a very thorough intern who never sleeps and doesn’t complain about typos.

This isn’t your standard Renovate setup (the bot-versus-bot comparison lives in Renovate vs Dependabot). This is Renovate configured for Kubernetes and Helm specifically, the custom managers, scheduling strategy, grouping rules, and the gotchas that bite you when you’re deploying to a cluster instead of a Node.js app.


Why Renovate Over Dependabot (or Manual)?

Dependabot is GitHub’s native tool, and it caught up on Kubernetes more than most write-ups admit. It ships a helm package ecosystem that reads Chart.yaml dependencies, Chart.lock, and the repository plus tag image pairs inside values.yaml. Its docker ecosystem updates image tags in plain Kubernetes manifests too. The old “Dependabot can’t do Helm” line is stale.

Where it still loses is configurability. Dependabot has no equivalent of a custom regex manager, so a YAML shape it doesn’t recognize is simply invisible. Grouping is limited to the groups key in dependabot.yml, scheduling granularity stops at daily, weekly, or monthly, and there’s no minimumReleaseAge to hold a release back until it has survived a week in public.

Manual updates are reliable until they’re not. You’ll miss a patch, forget to test it, ship a breaking chart change on Friday afternoon, or get burned when a new image version silently drops support for ARM64. There’s no audit trail, no consistency, no automation.

Renovate was built for monorepos and infrastructure repos. It ships five Helm managers out of the box (helmv3, helm-values, helm-requirements, helmfile, helmsman), custom regex managers for YAML shapes nobody standardized, cron scheduling so you don’t get 50 PRs on Monday, and grouping rules to batch related updates. It assumes you can’t test every image version independently, so it gives you the knobs to group them, rate-limit them, and merge them on your terms.


Getting Renovate Running

You have two paths: Mend’s hosted app or self-hosted.

For most home lab GitOps setups, the hosted app is the move. Install it from github.com/apps/renovate, authorize your repos, and you’re off. Manage installs and read job logs at developer.mend.io.

The free plan covers an unlimited number of public and private repos. The caps are on throughput, and as of September 2026 they are: one concurrent job per org, active repos scheduled every 4 hours, 1 vCPU and 3 GB RAM per job runner, 15 GB disk, and a 30 minute job timeout. A home lab GitOps repo scans in well under a minute, so none of that will bite you. One thing that will: Mend’s hosted GitLab.com app is offline indefinitely, so GitLab users self-host.

But the real power unlocks when you write a renovate.json config tailored to your setup.


Basic renovate.json for Kubernetes + Helm

Here’s a starter config that handles the essentials, Helm chart updates, container image updates, and scheduling:

renovate.json
{
"extends": ["config:recommended"],
"timezone": "America/Los_Angeles",
"schedule": ["* 22-23,0-4 * * 1-5", "* * * * 0,6"],
"labels": ["renovate", "automation"],
"ignorePaths": ["archive/**", "deprecated/**"],
"vulnerabilityAlerts": {
"labels": ["security", "urgent"],
"assignees": ["your-github-username"]
},
"packageRules": [
{
"matchDatasources": ["docker"],
"groupName": "Docker images",
"schedule": ["* 22-23,0-4 * * 1-5"]
},
{
"matchDatasources": ["helm"],
"groupName": "Helm charts",
"schedule": ["* 22-23,0-4 * * 0,6"]
},
{
"matchUpdateTypes": ["patch"],
"automerge": true,
"automergeType": "pr",
"automergeStrategy": "squash"
}
]
}

What’s happening here:

Notice what isn’t there: a helm block. There is no manager by that name, and "helm": {"enabled": true} is a config error the validator rejects. config:recommended already enables helmv3 for Chart.yaml dependencies, plus helm-values, helm-requirements, helmfile, and helmsman. Helm works with zero configuration.

This covers 80% of what you need. The remaining 20% is custom managers for edge cases.


Custom Managers: Taming Kubernetes YAML

Before you write a regex, check whether a built-in manager already covers you. Most people reach for a custom manager and then discover Renovate had it handled.

Here’s the classic case: you’re pinning Traefik in a values file like this:

traefik-values.yaml
image:
repository: traefik
tag: 3.6.1

The helm-values manager parses exactly that shape. Its problem is the filename. Its default file pattern is /(^|/)values\.ya?ml$/, so it matches values.yaml and nothing else. Widen the pattern and you’re done:

renovate.json
{
"extends": ["config:recommended"],
"helm-values": {
"managerFilePatterns": ["/(^|/)[\\w-]*values\\.ya?ml$/"]
}
}

One line of config, no regex to maintain. Custom managers earn their keep on shapes no built-in manager knows: an image pinned by tag and digest, a version buried in a ConfigMap, a Kustomize newTag field.

renovate.json
{
"extends": ["config:recommended"],
"pinDigests": true,
"customManagers": [
{
"customType": "regex",
"managerFilePatterns": ["/^clusters/.*\\.ya?ml$/"],
"matchStrings": [
"image:\\s+(?<depName>[\\w\\-\\./]+):(?<currentValue>[\\w\\-\\.]+)@(?<currentDigest>sha256:[a-f0-9]{64})"
],
"datasourceTemplate": "docker",
"versioningTemplate": "docker"
}
]
}

What’s going on:

Heads up: recent Renovate renamed fileMatch to managerFilePatterns in custom managers. The old key still works via auto-migration (you’ll just get a “config migration necessary” nag), but if you’re writing a config fresh, use managerFilePatterns and wrap regex values in slashes (/.../), plain strings are now treated as globs.

Custom managers are annoying to debug, so validate before you commit:

Terminal window
npx --yes --package renovate -- renovate-config-validator

That catches typos and invalid keys. It cannot tell you whether your matchStrings actually matched anything. For that, read the Dependency Dashboard issue Renovate opens in your repo: it lists every dependency Renovate found. If your image isn’t in that list, the regex missed, and staring at the empty PR list won’t tell you why.


Helm Chart Dependencies (The Easy Way)

If you’re using Helm properly, your charts have dependencies defined in Chart.yaml:

Chart.yaml
dependencies:
- name: argo-cd
version: "10.7.x"
repository: https://argoproj.github.io/argo-helm
- name: longhorn
version: "1.9.x"
repository: https://charts.longhorn.io

Get the chart name exactly right. The argo-helm repo publishes it as argo-cd. Write argocd and helm dependency update fails on a name that isn’t in the repository’s index.yaml, so Renovate has nothing to track. (Versions above are current as of September 2026: argo-cd 10.7.x, longhorn 1.9.x.)

The helmv3 manager picks these up with zero configuration, because config:recommended already enables it. No custom manager needed. It respects your version constraints (10.7.x bumps patch releases but not minor), and it checks the chart exists in the repository index before opening a PR.

Add this to your config to group all Helm updates together:

renovate.json
{
"packageRules": [
{
"matchDatasources": ["helm"],
"groupName": "Helm chart dependencies",
"schedule": ["* 20-23 * * 0"],
"reviewers": ["your-github-username"]
}
]
}

Scheduling and Grouping (So You Don’t Wake Up to 50 PRs)

This is where most people trip up. If you don’t schedule and group, Renovate will open a PR for every single version bump, and you’ll have 30 PRs by Monday morning, each one needing individual review and test cycles. That’s worse than doing it manually.

Here’s a smarter approach:

renovate.json
{
"extends": ["config:recommended"],
"timezone": "America/Denver",
"schedule": ["* 22-23,0-4 * * 1-5", "* 0-6 * * 0,6"],
"packageRules": [
{
"matchDatasources": ["docker"],
"matchUpdateTypes": ["patch", "minor"],
"groupName": "Docker image updates",
"groupSlug": "docker-updates",
"schedule": ["* 20-23 * * 1"],
"minimumReleaseAge": "7 days",
"automerge": true,
"automergeType": "pr",
"automergeStrategy": "squash"
},
{
"matchDatasources": ["docker"],
"matchUpdateTypes": ["major"],
"labels": ["breaking-change"],
"schedule": ["* 20-23 * * 5"],
"automerge": false
},
{
"matchDatasources": ["helm"],
"groupName": "Helm chart updates",
"schedule": ["* 2-6 * * 0"],
"minimumReleaseAge": "14 days"
},
{
"matchPackageNames": ["**prometheus**", "**grafana**", "**loki**"],
"groupName": "Observability stack",
"schedule": ["* 18-23 * * 3"]
}
]
}

The strategy:

Two things in that config are easy to get wrong.

Glob your package names. matchPackageNames takes exact strings or glob patterns, and for the docker datasource the package name is the full image path: grafana/grafana, docker.io/prom/prometheus, grafana/loki. A bare "grafana" matches the Helm chart called grafana and misses every image. The **grafana** glob catches both.

Give the schedule room. A schedule doesn’t trigger a Renovate run. It only permits one, and Renovate skips the repo entirely outside the window. On the free hosted plan your repo is scanned every 4 hours, so a two-hour window like * 22-23 * * 1 can be missed for weeks. Renovate’s own docs recommend at least 3 to 4 hours. That’s why the rules above use 20-23 rather than 22-23.

minimumReleaseAge means “don’t open a PR for a version that’s been out for less than X days.” It filters early-adopter pain and gives maintainers time to yank a bad release. Use it for that, not as a general slowdown: for a package that releases too often, a narrower schedule is the right tool.


ArgoCD and Flux Compatibility

Both ArgoCD and Flux are GitOps operators. Renovate doesn’t care which one you use, it just commits to your Git repo, and your operator syncs the changes. Here’s the shape of it:

With ArgoCD:

With Flux:

In both cases, Renovate just needs write access to your repo. No special integration needed. It’s blissfully simple.

But here’s a gotcha: if you have a commit hook or branch protection rule that runs tests, Renovate respects it. Your CI will run against Renovate’s PR, and if the tests fail, the PR stays open until you fix it. This is actually good, you catch bad chart versions before they’re deployed, but it means you need solid test coverage on your manifests. At minimum, a helm lint and a kube-score check.


Common Mistakes

Mistake 1: Not pinning versions in your base Helm charts. If your Chart.yaml says version: "*", Renovate will open a PR for every new version, even breaking ones. Use semver constraints: "3.x" for minor/patch safety, ">=3.0.0,<4.0.0" for explicit ranges.

Mistake 2: Putting pinDigests in the wrong place. If you’re pinning image digests (good practice), set pinDigests: true at the top level of renovate.json or inside a packageRules entry. It is not a customManagers field, and nesting it there fails validation. Your regex still has to capture currentDigest alongside currentValue, or you’ll end up with a fresh tag pointing at a stale digest.

Mistake 3: Opening too many PRs at once. If you don’t schedule and group, Renovate becomes noise, and you’ll disable it. Start with one grouping strategy (e.g., “all Docker images weekly”), prove it works for a month, then add complexity.

Mistake 4: Not configuring vulnerabilityAlerts. Security patches should never be grouped with regular updates. They should be fast-tracked, labeled, and reviewed immediately. Make them impossible to ignore.

Mistake 5: Forgetting branch protection interacts with automerge. If your repo requires branch protection (reviews, status checks), Renovate’s PRs will respect that. If you trust Renovate’s patch updates, set up auto-merge, but only for patch versions. Major versions still need human eyes.


The Endgame

After a few months of Renovate doing its thing, you’ll have:

It’s not magic. It’s just the boring work automated away so you can focus on the stuff that actually matters, testing, incident response, and building the next thing.

Set it and forget it. Your future self will thank you.

Common Questions

Does Dependabot support Helm charts now?

Yes. Dependabot ships a helm package ecosystem that reads Chart.yaml dependencies, Chart.lock, and repository/tag image pairs in values.yaml. Its docker ecosystem updates image tags in Kubernetes manifests. Renovate still wins on custom managers, grouping, and minimumReleaseAge. Basic Helm awareness stopped being the difference.

Is the free Mend Renovate plan enough for a home lab?

Yes. Mend Renovate Community Cloud covers unlimited public and private repos. The caps are throughput: one concurrent job per org, active repos scanned every 4 hours, 1 vCPU and 3 GB RAM per job, and a 30 minute timeout. A single GitOps repo scans in under a minute.

Do I need a custom manager for images in a Helm values file?

Usually no. The built-in helm-values manager already parses the image.repository plus image.tag shape. It only matches files literally named values.yaml, so if yours is traefik-values.yaml, widen helm-values.managerFilePatterns instead of writing and maintaining a regex.

Why is Renovate ignoring my schedule?

A schedule permits runs. It never triggers them. If the hosted plan scans your repo every 4 hours and your window is two hours wide, most windows get missed entirely. Renovate’s docs recommend windows of at least 3 to 4 hours. Widen the window before you debug anything else.

Can I safely auto-merge Renovate PRs in a GitOps repo?

Yes, for patch updates with branch protection turned on. Set automerge: true and automergeType: "pr", then require passing status checks so a failing helm lint or kube-score run blocks the merge. Add minimumReleaseAge so yanked releases never reach you. Never auto-merge majors.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
Falco + Trivy in k3s: Runtime Security on Small Clusters
Next Post
External Secrets Operator + Vault on k3s

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts