> For the complete documentation index, see [llms.txt](https://postica.gitbook.io/binding-system-3/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://postica.gitbook.io/binding-system-3/project-tools/diagnostics/refactoring.md).

# Refactoring

Renaming a field no longer breaks the bindings that pointed at it.

{% hint style="success" %}
**Learn by doing:** [Surviving a Rename](/binding-system-3/tutorials/surviving-a-rename.md) triggers this on purpose and works through the window, including what it cannot repair.
{% endhint %}

A binding stores a path as text. Rename `health` to `currentHealth` and every binding that pointed at it would be pointing at nothing.

Instead, the member is collected and you are asked, once, where it went. Every binding of it then follows.

<figure><img src="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FhgXHSI8T2AKSuRAOcRye%2FScreenshot%202026-09-28%20at%2018.15.25.png?alt=media&amp;token=c7a29200-f12a-4c4a-bcaf-3bf7b915449d" alt="" width="563"><figcaption><p>The refactoring window after a rename</p></figcaption></figure>

## One decision per member

This is the shape of the whole tool, and it is worth stating before anything else. Fifty bindings pointing at one renamed field is **one row and one decision**, not fifty.

Each row carries the number of bindings waiting on it. Hover the count to see which ones.

## How members get here

Three things feed the window, and knowing which is which explains why the count on a row can grow.

<table><thead><tr><th width="290">Source</th><th>What happens</th></tr></thead><tbody><tr><td><strong>A proxy binding that fails to resolve</strong></td><td>When a <a href="/binding-system-3/overview/proxy-bindings.md">proxy binding</a> is loaded and the field it drives is gone, it reports itself. The window opens by itself the first time this happens after a code change. This only covers proxies in the scenes and prefabs that are actually loaded.</td></tr><tr><td><strong>A check of the loaded proxies</strong></td><td>A proxy whose <em>source</em> member was renamed reports nothing by itself: it simply fails to read. So after every script reload, and whenever you open a scene, the loaded proxy bindings are checked for source members that are gone, with the validator's own rules. The window opens when one is found. A member you already decided about is followed without asking.</td></tr><tr><td><strong>The</strong> <a href="/binding-system-3/project-tools/diagnostics/validator.md"><strong>Bindings Validator</strong></a></td><td>Press <strong>Refactor renamed members</strong> in the validator, or <strong>Find more in project</strong> here, and every binding whose member was renamed or moved is collected, <strong>including the ones in scenes nobody has open</strong>. This is the one that reaches a whole project.</td></tr></tbody></table>

{% hint style="info" %}
The validator is the route to use after a real rename. A `Bind<T>` field in a scene that is not open never raises anything by itself, so before the validator existed those bindings simply stayed broken until somebody opened the scene. **Find more in project** runs a whole-project validation and brings them all here.
{% endhint %}

## The three answers

<table><thead><tr><th width="200">Choice</th><th>What it does</th></tr></thead><tbody><tr><td><strong>Replace</strong></td><td>Point every binding at another member. A picker opens; see below.</td></tr><tr><td><strong>Switch off</strong></td><td>Turn every binding of that member off. Each field keeps the literal value it already holds, so nothing is lost, and a proxy binding is removed outright because a proxy has no value of its own to keep.</td></tr><tr><td><strong>Ignore</strong></td><td>Leave these bindings exactly as they are and stop asking about this member.</td></tr></tbody></table>

Once a row is answered, a fourth button appears: **Undecide**, which clears the decision and puts the row back to unanswered.

The footer keeps a running count of how many members are still undecided and how many bindings **Apply** will actually change. Nothing is written until you press it.

**Ignore all** in the toolbar answers every remaining row that way at once, which is the honest choice when a rename is not the thing you want to deal with right now.

### The picker

**Replace** opens a search dropdown with three branches:

<table><thead><tr><th width="230">Branch</th><th>What it contains</th></tr></thead><tbody><tr><td><strong>Best matches</strong></td><td>Members of the same type whose name is close to the old one and whose value can stand in for it, ranked by how close. For a plain rename the answer is here and it is at the top. An exact name match is labelled as such.</td></tr><tr><td>The type the member left</td><td>Everything else on that type, in case the rename was less obvious than the ranking thinks.</td></tr><tr><td><strong>All types</strong></td><td>The whole project, by namespace, for a member that moved somewhere else entirely.</td></tr></tbody></table>

Candidates are filtered to values that can stand in for the old one: the same type, something assignable to it, or something the [converters](/binding-system-3/pipeline/converters.md) can turn into it, which is what keeps numeric widenings in the list.

## Applying

Press **Apply**.

If any row is still undecided you are told first, and can go back or apply the rest. Rows set to **Switch off** are counted and confirmed separately, because that is the answer that changes behaviour rather than repairing it.

Everything **Apply** writes goes into **a single undo step**. If the result is not what you expected, one undo puts the project back.

**Close** writes nothing. The questions are asked again next time the members come up.

{% hint style="warning" %}
If [refactoring is disabled](/binding-system-3/reference/settings.md#refactor-manager), a proxy binding that fails to resolve is **removed with no prompt**. Ordinary `Bind<T>` fields are untouched either way, but there is no window and no decision. Leave it enabled.
{% endhint %}

## Decisions become rules

Every decision you apply is kept as a **rule**, written to `Library/bs-refactors.json`. The same rename is not asked about twice, and a binding in a scene you open next week follows a decision you already made. A rename followed through `[FormerlySerializedAs]` is kept the same way.

A rule is dropped automatically when the member it was about comes back, because then it is a decision about nothing.

The rules are listed in **Project Settings ▸ Binding System ▸ Configuration ▸ Refactor Manager**, one row each: the type and the member that went away, an arrow, and what its bindings do now.

<table><thead><tr><th width="250">The rule reads</th><th>What it means</th></tr></thead><tbody><tr><td>A member name</td><td>Bindings of the old member are pointed at this one. The type is shown too when the member moved to another type.</td></tr><tr><td><strong>Switched off</strong></td><td>Bindings of the member are switched off, each field keeping its literal value.</td></tr><tr><td><strong>Left as it is</strong></td><td>Bindings of the member are left alone, and nobody is asked about them.</td></tr><tr><td>A member name, in red</td><td>The member it was pointed at has gone as well. Forget the rule to be asked again.</td></tr></tbody></table>

Forget a single rule with the **⌫** button on its row, or all of them with **Forget All Rules**. Bindings already rewritten stay as they are; a forgotten member is asked about again the next time one of its bindings comes up. The same panel reports how many members are currently waiting and opens the window.

## Settings

**Project Settings ▸ Binding System ▸ Configuration ▸ Refactor Manager**

<table><thead><tr><th width="290">Setting</th><th>What it does</th></tr></thead><tbody><tr><td><strong>Enable Refactoring</strong></td><td>On: you get the window and can choose. Off: an unresolvable proxy binding is removed with no prompt.</td></tr><tr><td><strong>Prefer Renaming Auto Fix</strong></td><td>Follow <code>[FormerlySerializedAs]</code> and repair the binding without asking when the match is unambiguous.</td></tr><tr><td><strong>Enable Unity Classes Refactoring</strong></td><td>Also handle members of Unity's own types. Useful across an editor upgrade.</td></tr></tbody></table>

**Prefer Renaming Auto Fix** is the setting to turn on once you trust the tool. A field carrying `[FormerlySerializedAs("health")]` is then followed silently, through a chain of renames if there is one, and no window appears.

## What it can and cannot see

<table><thead><tr><th width="290">Case</th><th>What happens</th></tr></thead><tbody><tr><td>A field renamed</td><td>Handled, and the new name is usually the top suggestion.</td></tr><tr><td>A method renamed, or its parameters changed</td><td>Handled. The finding says which, and the picker filters accordingly.</td></tr><tr><td>A field moved to another type</td><td>Handled. The picker lists candidates across types, and the binding's recorded source type is updated when the member was the first thing its path walked.</td></tr><tr><td>A field's type changed</td><td>Handled. Candidates are filtered to values that can stand in.</td></tr><tr><td>A field deleted outright</td><td>Handled, with <strong>Switch off</strong> as the honest answer.</td></tr><tr><td>Bindings in scenes that are not open</td><td>Handled, through <strong>Find more in project</strong>. They are rewritten in place when you press Apply, opening each scene as needed.</td></tr><tr><td>A modifier or converter <em>class</em> renamed</td><td><strong>Not handled.</strong> Those are stored by class name through <code>[SerializeReference]</code>, not as a path. The <a href="/binding-system-3/project-tools/diagnostics/validator.md">validator</a> reports them as <em>Modifier type is missing</em>, and the repair is to pick the modifier again.</td></tr></tbody></table>

{% hint style="success" %}
`[FormerlySerializedAs]` is still the right tool for keeping Unity's own serialization working across a rename, and it composes with this: the attribute keeps the **value**, refactoring keeps the **bindings**, and with **Prefer Renaming Auto Fix** on the attribute drives both. Use it.
{% endhint %}

## After a big refactor

1. Let the window handle whatever announced itself.
2. Press **Find more in project**, or run the [validator](/binding-system-3/project-tools/diagnostics/validator.md) over the whole project and use **Refactor renamed members** there. This is the step that reaches the scenes nobody opened.
3. Answer the rows, press **Apply**, and re-run the validator. A rename that repaired 49 of 50 bindings looks exactly like one that repaired all of them until you look.
4. Check the [Dependency Graph](/binding-system-3/project-tools/diagnostics/dependency-graph.md) with the changed type in **Focus**, to confirm the connections you expected survived.

## Related pages

* [Bindings Validator](/binding-system-3/project-tools/diagnostics/validator.md): what finds the broken bindings in the first place.
* [Error Visualization](/binding-system-3/project-tools/diagnostics/errors.md): what a broken binding looks like on the row before you repair it.
* [Reserializer](/binding-system-3/project-tools/diagnostics/reserializer.md): the neighbouring problem, changing a field's type to or from a bind type.
* [Field Rerouting](/binding-system-3/reference/extending/field-rerouting.md): redirecting a bound field permanently, by design rather than by accident.
