# scene-ref-attribute: Unity references resolved in the editor instead of at Awake

> The Scene Reference Attribute is a Unity C# package that resolves component and interface references during OnValidate and serialises them into the scene or prefab, so runtime code does not call GetComponent in Awake. It supports five search scopes, interface references, and per-attribute flags.

**KyleBanks/scene-ref-attribute** — Unity C# attribute for serializing component and interface references within the scene or prefab during OnValidate.

- Repository: https://github.com/KyleBanks/scene-ref-attribute
- Stars: 579 · Forks: 69
- Language: C#
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/kylebanks-scene-ref-attribute

## The package moves reference resolution out of Awake and into OnValidate

The Scene Reference Attribute is a Unity C# attribute for serializing component and interface references within the scene or prefab during OnValidate, rather than using GetComponent functions in Awake, Start, or OnEnable at runtime. The project states three aims. A simple set of tags for declaring dependency locations. Resolution, validation, and serialisation of references, including interface types. And determinate results, so you never have to worry about Unity losing your references because they will always be safely regenerated. The audience is a Unity developer who has watched a scene load hitch and decided the cost of a runtime lookup is not worth paying on every load, and who also thinks an inline declaration reads better than a block of Find calls in Awake.

## The before and after shows exactly what moves where

The README draws the contrast with a concrete pair of examples. The before version declares six serialised fields, finds them in Awake with `FindObjectByType`, `GetComponent`, `GetComponentInChildren`, `GetComponentInParent`, and `GetComponentsInChildren`, and then asserts in OnValidate that the button was assigned. The after version keeps the serialised fields but adds a scope attribute to each one:

```cs
[SerializeField, Self] private Collider _collider;
[SerializeField, Child] private Renderer _renderer;
[SerializeField, Parent] private Rigidbody _rigidbody;
[SerializeField, Anywhere] private Button _button;
```

and the OnValidate body becomes a single call to `this.ValidateRefs()`. The Awake method disappears entirely. That is the whole trick. Instead of declaring where a reference lives and then finding it at runtime, you declare where it lives and the editor finds it for you, and the resolved value is written into the scene or prefab so it is already there when the game runs.

## Five scopes map directly onto the GetComponent variants

The scope attributes are named after the search they perform, which makes them easy to reason about. `Self` looks for the reference on the same game object as the attributed component using `GetComponent` or `GetComponents`. `Parent` looks on the parent hierarchy using `GetComponentInParent`. `Child` looks on the child hierarchy using `GetComponentInChildren`. `Scene` looks for the reference anywhere in the scene using `FindAnyObjectByType` and `FindObjectsOfType`. `Anywhere` only validates that the reference is not null and relies on you to assign it yourself, which is the escape hatch for a reference that must be dragged in by hand. The mapping is deliberate, so the semantics of a scope are the semantics of the Unity call it wraps, and there is no new mental model to learn.

## Interface references work by wrapping the type in InterfaceRef

By default Unity does not allow you to serialise interfaces, and this package handles that with a wrapper type. The README shows a single interface and an array of interfaces, both declared with the `Self` scope:

```cs
[SerializeField, Self] private InterfaceRef<IDoorOpener> _doorOpener; 
[SerializeField, Self] private InterfaceRef<IDoorOpener>[] _doorOpeners; 
```

From there the reference is serialised like any other component reference, with the interface itself reachable through the `Value` property:

```cs
IDoorOpener doorOpener = this._doorOpener.Value;
doorOpener.OpenDoor();
```

The underlying implementation is a `MonoBehaviour` in the scene, and the wrapper stores a reference to that component while presenting the interface type to your code. The repository layout shows how much is involved: there is an `InterfaceRef.cs`, an `InterfaceRefPropertyDrawer.cs` for the inspector, and a `ISerializableRef.cs` interface, alongside `SceneRefAttribute.cs`, its own property drawer, and a `SceneRefAttributeValidator.cs`.

## Flags decide what counts as a result and when validation fails

Each attribute accepts optional flags that customise its behaviour, and the README documents each one precisely. `Optional` means validation will not fail for empty results, or for null in the case of non-array types. `IncludeInactive` affects only `Parent`, `Child`, and `Scene`, and decides whether inactive components are included, with only active components found by default, matching the behaviour of the GetComponent and FindObjects calls it wraps. `ExcludeSelf` affects only `Parent` and `Child`, and by default components on the same GameObject are included. `Editable` affects `Parent`, `Child`, and `Scene`, and lets you override the result in the inspector, which the README describes as useful when two children would both satisfy a reference and you want to pick one. `EditableAnywhere` has the same effect but will not validate the supplied reference, so it acts as a manual reference with an automatic fallback.

## Custom filters let you narrow results by your own logic

The package also supports filtering references with custom logic, through a `SceneRefFilter` interface and a `filter` parameter on the attribute. The README's example is a `StealthAnimations` class that applies stealth related game logic to all child `Animator` components, setting a hashed `StealthState` integer on each one every frame. The problem the filter solves is efficiency. Checking every child animator for the parameter each frame is wasteful when many children lack it, so the animators are pre-filtered at validation time instead. The repository has a `SceneRefFilter.cs` file, a `ReflectionUtil.cs`, and a `SceneRefAttributeValidator.cs` that does the work, along with `SceneRefValidatorOnSave.cs` for validation at save time. The design point is that the filter runs once, in the editor, rather than every frame at runtime, which is where the cost actually was.

## Two ways to use it, and a package you install by hand

There are two integration paths. The `ValidateRefs` function is made available as a MonoBehaviour extension for ease of use on any MonoBehaviour subclass, and handles finding, validating, and serialising the references in the editor so they are always available at runtime. Alternatively you can extend `ValidatedMonoBehaviour` instead, and `ValidateRefs` is invoked automatically. Installation has a basic route and a UPM route. The basic one is to clone the repository, or download it as a zip and unzip it, into your `Assets/` directory. The UPM route is a command line install:

```bash
openupm add com.kylewbanks.scenerefattribute
```

The package metadata names it `com.kylewbanks.scenerefattribute` with a display name of Scene Reference Attribute, version 0.15.0, and the MIT licence. The repository also carries a `KBCore.Refs.asmdef`, so the code lands in its own assembly definition rather than compiling into your default assembly, and the last push was on 2026-10-05 with the v0.15.0 release.

## Conclusion

scene-ref-attribute fits a Unity team that is seeing frame rate hitches when scenes are addeditively loaded, or that has decided the inspector should hold the references rather than a runtime lookup, and that wants interface references to survive serialisation. It is the wrong tool if your references are already inspector-assigned and validated, since the package's value is doing the assignment for you, and it is the wrong tool for a project that would rather not add a third party assembly to its build. Before you adopt it, read the Flags section carefully, because `Optional`, `IncludeInactive`, `ExcludeSelf`, `Editable`, `EditableAnywhere` and `Filter` change what gets found and when validation fails, and check the release notes since the package version is still below 1.0.

## FAQ

### What does the scene-ref-attribute package do in Unity?

It is a Unity C# attribute for serializing component and interface references within the scene or prefab during OnValidate, rather than using GetComponent functions in Awake, Start, or OnEnable at runtime. The resolved references are written into the scene so they are available without a runtime lookup.

### How do I install scene-ref-attribute in a Unity project?

You can clone the repository, or download it as a zip and unzip it, into your `Assets/` directory. For UPM, install it from the command line with `openupm add com.kylewbanks.scenerefattribute`, using the package name `com.kylewbanks.scenerefattribute`.

### What is the difference between the Self, Child, Parent, Scene, and Anywhere attributes?

Self looks on the same game object using GetComponent, Parent looks on the parent hierarchy using GetComponentInParent, Child looks on the child hierarchy using GetComponentInChildren, Scene looks anywhere in the scene using FindAnyObjectByType and FindObjectsOfType, and Anywhere only validates that the reference is not null and relies on you to assign it.

### How do I serialize an interface reference with scene-ref-attribute?

Wrap it in the `InterfaceRef` type, for example `InterfaceRef<IDoorOpener>`, and declare it with a scope attribute. The interface is then reachable through the `Value` property, and the reference serialises like any other component reference.

### What do the Flag options on scene-ref-attribute attributes control?

`Optional` stops validation failing on empty or null results, `IncludeInactive` includes inactive components for Parent, Child and Scene, `ExcludeSelf` drops components on the same GameObject for Parent and Child, `Editable` lets you override the result in the inspector, `EditableAnywhere` does the same without validating the supplied reference, and `Filter` applies your own custom logic.

## Sources

- [Issues](https://github.com/KyleBanks/scene-ref-attribute/issues)
- [KyleBanks/scene-ref-attribute on GitHub](https://github.com/KyleBanks/scene-ref-attribute)
- [License: MIT](https://github.com/KyleBanks/scene-ref-attribute/blob/main/LICENSE)
- [README](https://github.com/KyleBanks/scene-ref-attribute/blob/main/README.md)
- [Releases](https://github.com/KyleBanks/scene-ref-attribute/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kylebanks-scene-ref-attribute
