Process

Why I stopped Renovate from auto-merging my Unity Editor version

  • Renovate
  • Unity
  • CI
  • Dependency Management
  • Game Development

I almost let a bot upgrade my Unity Editor behind a green check. A Renovate PR showed up on one of my sandboxes, labelled it a patch update, and my config auto-merges patches — so the only reason it didn’t land on its own is that I happened to look at the PR table before the merge fired.

https://github.com/tang3cko/Sandbox_001/pull/3

This post is about why a Unity Editor bump is the one “patch” you don’t want auto-merged, how Renovate’s unity3d manager produces these PRs, and the one-rule fix I pushed to the default.json5 I share across my repos.

The PR that nearly merged itself

One file changed: ProjectSettings/ProjectVersion.txt. Two lines in it, both pointing at the same Unity build.

-m_EditorVersion: 6000.3.11f1
-m_EditorVersionWithRevision: 6000.3.11f1 (3000ef702840)
+m_EditorVersion: 6000.3.17f1
+m_EditorVersionWithRevision: 6000.3.17f1 (cf0352b38e81)

Renovate’s PR table rendered it as a single coupled change and classified it as a patch:

| Unity Editor | patch | 6000.3.11f1 (3000ef702840) → 6000.3.17f1 (cf0352b38e81) |

That “patch” label is the problem, because my shared config treats patches as safe enough to merge unattended:

packageRules: [
  {
    matchUpdateTypes: ["minor", "patch", "pin", "digest"],
    automerge: true,
  },
],

For an npm dependency that rule is exactly what I want — a 1.2.3 → 1.2.4 patch with green CI doesn’t need my attention. So the same rule, applied to ProjectVersion.txt, would have flipped my Editor version and merged it without anyone deciding to upgrade. That’s the trap.

(The reason the table shows the version twice is the manager itself. Renovate’s unity3d manager reads ProjectVersion.txt and, per its docs, updates m_EditorVersion and m_EditorVersionWithRevision together as one coupled change — “Both are updated together.” So you never get two half-bumped PRs, but you also can’t separate the human-readable version from the revision hash.)

Why the Editor version isn’t a normal dependency

A library version is a number your build resolves. The Editor version is a number that decides which program is even allowed to open the project. m_EditorVersion: 6000.3.17f1 is the project saying “you must open me with Unity 6000.3.17f1,” and Unity Hub enforces it — open the project with a different installed Editor and you get the version-mismatch prompt before anything loads.

So when Renovate flips that line and merges it, the project starts demanding an Editor build that nobody on the team, and no CI runner, necessarily has installed. The moment it lands, opening or building can stall until everyone goes and downloads that exact Editor — and on a shared machine or a build agent, “go install a 7 GB Editor” is not a thing that happens silently in the background. Upgrading the Editor is a coordinated decision: someone picks the version, installs it, checks the project still opens, and tells the rest of the team. It is not a thing a bot should slip in behind a passing pipeline.

The version bump being small makes it worse, not better. A major-looking jump would have caught my eye in the PR list. A patch is exactly the shape of change I’ve trained myself to merge without reading.

What I tried first

My first instinct was to match the package by name and turn off auto-merge just for it. That turned out to be the fiddly path. The unity3d manager doesn’t expose a clean, stable package name to match on the way an npm dependency does — pinning a matchPackageNames or matchDepNames rule to “the Unity Editor” means guessing at the string the manager generates, and it’s the kind of match that silently stops working when the internals shift.

The reliable lever is one level up: match the manager, not the package. Every PR of this shape comes from exactly one manager, unity3d, and that manager does nothing else. So matching matchManagers: ["unity3d"] catches every Editor bump across every repo and nothing else, with no fragile name string to maintain. This is also the move I kept seeing recommended in Renovate discussions, and once I tried both, the reason was obvious.

The fix

I added one rule to the shared default.json5:

{
  // Skip Unity Editor version bumps: the version in ProjectVersion.txt requires every
  // developer and CI machine to have that exact Unity Editor installed, so upgrades must
  // be a deliberate manual decision rather than an automated update.
  matchManagers: ["unity3d"],
  enabled: false,
},

enabled: false means the PR is never raised in the first place — a true skip, not “raise it but hold the merge.” After I committed this to my shared config, Renovate autoclosed the exact PR above on its next run, which is the closest thing to a test I get here: the rule reached the repo, and the bump it had already opened went away on its own.

If you’d rather keep the visibility — see that an Editor update exists, just don’t merge it automatically — set automerge: false on the same matchManagers rule instead of disabling it. You get a standing PR you can act on deliberately. I went with the full skip because for a solo evening project an open PR I’m choosing to ignore is just noise, and I’d rather decide to upgrade the Editor by going to Unity Hub than by remembering not to click merge.

This lives in the same place as the rest of my cross-repo discipline — a single config I pull into every project so I only have to learn each of these lessons once. I wrote about that habit, in its Claude Code form, here:

PostA personal standards repo, shaped as Claude Code SkillsWhy I keep my Unity rules in a separate tang3cko/standards repo, and how each lesson lands as a Claude Code Skill that fires automatically the next time I touch the same domain.

What I’d still change

The rule is blunt on purpose, and the bluntness has a cost: I now get zero signal when a new Editor patch ships. With enabled: false there’s no PR, no notification, nothing — I find out a new 6000.3.x exists when I happen to open Unity Hub. The automerge: false variant trades noise for that signal, and I keep going back and forth on whether the standing-PR version is actually the better default for a team repo where someone else might want to drive the upgrade.

The other thing I haven’t solved is the coupling itself. Because the manager bundles m_EditorVersion and the revision hash, there’s no clean way to say “tell me about minor Editor versions but ignore pure revision re-tags.” For now I treat all of it as one off switch, which is fine for one developer and probably too coarse for a real team.

Wrap-up

Auto-merging patches is a good default right up to the moment the “patch” is your toolchain instead of a library. The Unity Editor version sits in a dependency file, gets a version number, and travels through Renovate like any npm package — and none of that makes it safe to bump without a human deciding to. One manager-level rule keeps the bot out of that decision. Back to building things in the Editor I chose on purpose.

References