Unity prefab overrides, YAML identity and UnityYAMLMerge
Document status:
reviewed. Canonical source.
Summary
Unity serializes scenes and prefabs as a sequence of YAML documents, one per engine object, each addressed by a signed 64-bit local identifier (fileID) and a class identifier tag. Cross-file references combine the target file’s .meta GUID with a fileID. Prefab instances are not expanded in the containing file; a PrefabInstance document stores a source reference and an override set (m_Modifications, added/removed components and GameObjects), and placeholder documents marked stripped stand in for referenced nested objects. Prefab variants reuse the same mechanism with a parentless root instance. UnityYAMLMerge performs a three-way merge of these files by treating specified arrays as identity-keyed sets, excluding volatile paths, and comparing floats with tolerances; it falls back to a user-specified textual tool for unresolved conflicts. Text serialization must be enabled for any of this to apply. Known failure classes are order instability of override lists, local-only identity that differs between prefab assets, and a YAML dialect that is not meant to be externally produced.
Evidence
- Unity writes each object of a scene as a separate YAML document introduced by
---; the tag!u!<n>encodes the class ID and&<n>the object’s file-local ID. Unity Manual, “Format description” (Manual/FormatDescription.html), retrieved 2026-08-29. - Header lines are
%YAML 1.1and%TAG !u! tag:unity3d.com,2011:; references to other objects are{fileID: n}; asset references are{fileID: n, guid: <32 hex>, type: t}; the scene ends with aSceneRootsdocument listing ordered root transforms. Unity Manual, “YAML scene example” (Manual/YAMLSceneExample.html), retrieved 2026-08-29. - A prefab instance is a document of class ID
1001and typePrefabInstancewithm_SourcePrefab: {fileID: 100100000, guid: ..., type: 3};100100000is the prefab asset handle created at import. Unity Manual 6000.6, “YAML serialization of prefabs” (Manual/yaml-prefab-serialization.html), retrieved 2026-08-29. - The
m_Modificationblock containsm_TransformParent,m_Modifications,m_RemovedComponents,m_RemovedGameObjects,m_AddedGameObjects,m_AddedComponents. Eachm_Modificationsentry hastarget,propertyPath,value,objectReference. Same page. - Referenced nested objects appear as placeholder documents tagged
stripped, carrying onlym_CorrespondingSourceObject,m_PrefabInstanceandm_PrefabAsset. Same page; also Unity blog “Understanding Unity’s serialization language, YAML” (N. A. Borromeo), section “Prefab instances, Nested Prefabs, and Variants”, retrieved 2026-08-29. - A variant is identified by
m_Modification.m_TransformParentequal to{fileID: 0}on the rootPrefabInstance. Same manual page; same blog section. fileIDis local to a file and “can be repeated in different files”; cross-file identity is (GUID from.meta, fileID). Unity blog, section on cross-file references, retrieved 2026-08-29.- Replacing a nested prefab’s GUID by hand loses overrides because object
fileIDs in the replacement prefab “will differ” from those referenced bym_CorrespondingSourceObject. Unity blog, same section (NUIF reading: identity is asset-scoped, not semantic). - Local file IDs “are signed 64-bit values and can be negative”;
GlobalObjectIdcasts them toulong, so the sign is lost; the docs advise not relying ontargetObjectIdto find an object. Unity Scripting API,GlobalObjectId, retrieved 2026-08-29. - Overrides on a prefab instance are property values, added/removed components, and added/removed child GameObjects; an overridden value “always takes precedence” over the asset value; root instance position and rotation are not explicit overrides. Unity Manual, “Prefab instance overrides” (
Manual/PrefabInstanceOverrides.html), retrieved 2026-08-29. - A variant “inherits properties from a base prefab”; overrides take precedence; variants can be based on variants; “Apply all to Prefab Variant parent” pushes overrides one level up. Unity Manual, “Prefab variants” (
Manual/PrefabVariants.html), retrieved 2026-08-29. - Nested prefabs “keep their links to their own prefab assets” while forming part of another prefab; adding one from the Hierarchy is itself recorded as an override. Unity Manual, “Nested prefabs” (
Manual/NestedPrefabs.html), retrieved 2026-08-29. - Asset Serialization Mode defaults to Force Text; the setting exists “to help with version control merges”; a separate option writes references on one line “which reduces version control noise”. Unity Manual, “Editor settings” (
Manual/class-EditorManager.html), retrieved 2026-08-29. UnityYAMLMergeis shipped inEditor/Data/Tools(Windows) andUnity.app/Contents/Helpers(macOS); it can be run from the command line and configured as a merge driver for P4V, Git, Mercurial, SVN, TortoiseGit, UVCS and SourceTree;mergespecfile.txtdeclares fallback tools for unresolved conflicts. Unity Manual, “Smart merge” (Manual/SmartMerge.html), retrieved 2026-08-29.mergerules.txthas four sections. Arrays:set *.GameObject.m_Component *.fileID,set *.Prefab.m_Modification.m_Modifications target.fileID target.guid propertyPath,plain *.MeshRenderer.m_Materials,plain *.Renderer.m_Materials; the default for unlisted arrays is a hybrid heuristic match. Exclusions: paths such as*.SpriteRenderer.m_ColorandexcludeIfContains *.MonoBehaviour.* x y z; excluded paths modified on both sides become conflicts. Comparisons: relative/absolute epsilons such asfloat *.Transform.m_LocalPosition.x 0.0000005andfloat *.Transform.m_LocalRotation.x 0.00005 0.001. Unity Manual 6000.4, “Smart merge”, retrieved 2026-08-29.- UnityYAML “does not support the full YAML specification”; the manual states that users “cannot externally produce or edit UnityYAML files”; unsupported features include comments, multiple documents in the YAML sense, tags and complex keys. Unity Manual, “UnityYAML” (
Manual/UnityYAML.html), retrieved 2026-08-29. - Unity staff (MirceaI) state
m_Modificationsis sorted bytargetthenpropertyPath, but the internal representation oftargetdepends on load order, so entries with different GUIDs are “not … stable in different Editor sessions”, producing spurious diffs; reported on 2022.3.20 long-term support (LTS) with references back to 2019. Unity Discussions thread 943063, retrieved 2026-08-29.
Mechanism
Data model. A file is an ordered list of documents (classID, fileID, body). fileID is an int64 unique within the file. A reference is either intra-file {fileID} or inter-file {fileID, guid, type} where guid is the 128-bit identifier stored in the referenced asset’s .meta file and type distinguishes built-in, importer-generated and native assets. A GameObject owns an ordered m_Component array of references; a Transform owns m_Father and an ordered m_Children array; containment is therefore encoded twice (parent pointer and child list) and both must agree.
Prefab instances. Instead of copying the source hierarchy, the file stores one PrefabInstance document. Its override set is a list of (target, propertyPath, value, objectReference) tuples where target is an inter-file reference to an object inside the source prefab, and propertyPath is a dotted path into that object’s serialized property tree (m_LocalPosition.x, m_Name, array indices). Structural overrides are separate lists: removed components, removed GameObjects, added GameObjects, added components. Any object in the instance that must be referenced from the containing file (as a parent transform or as a reference target) is materialized as a stripped placeholder document with its own fileID; the placeholder records m_CorrespondingSourceObject (identity in the source asset) and m_PrefabInstance (the owning instance). Resolution reconstructs the full object graph by instantiating the source prefab, applying m_Modifications in order, applying structural add/remove lists and binding placeholders to the instantiated objects. A prefab variant is a prefab file whose root is a PrefabInstance with m_TransformParent = {fileID: 0}; nesting and variants are therefore the same mechanism composed recursively (variant of variant, instance inside variant).
Authored versus resolved. The saved file contains only authored opinions: the source reference and the sparse override set. The Editor materializes the resolved GameObject graph in memory; Apply moves overrides down into the asset and Revert deletes them. Because the file omits the resolved graph, any change in the source asset is reflected on load. Root position/rotation are treated as always-instance-local and are not counted as overrides.
Merge. UnityYAMLMerge parses base, ours and theirs into document trees keyed by (classID, fileID). Within a document it merges mappings key-wise. Arrays declared set are matched by the listed key paths (for m_Component, by fileID; for m_Modifications, by (target.fileID, target.guid, propertyPath)), so insertions and removals on both sides merge without positional conflicts. Arrays declared plain merge positionally. Unlisted arrays use a heuristic hybrid. Excluded paths are never auto-merged; if both sides changed them the result is a conflict. Float comparison uses per-path epsilons so that re-serialization noise is not reported as change. Unresolved conflicts are delegated according to mergespecfile.txt, typically to an interactive textual tool over the partially merged file. The tool is a structural three-way merge over identity-keyed trees rather than a semantic merge: it does not know that m_Father and m_Children must agree, nor that an override’s target must exist in the referenced prefab.
Failure classes (source-documented unless marked interpretation).
- Identity scope:
fileIDis file-local; identity of the “same” object in two prefab assets is unrelated, so replacing a source prefab invalidatesm_CorrespondingSourceObjecttargets and overrides are lost (Unity blog). - Sign loss: negative
fileIDs are reinterpreted inGlobalObjectId(Scripting API). - Ordering instability:
m_Modificationsorder depends on an internaltargetrepresentation that varies with load order, producing spurious diffs and merge noise (Discussions 943063). - Dual encoding of containment: parent pointer and child arrays can be merged independently and disagree (interpretation from the format description; the
setrule keyed onfileIDform_Componentdoes not coverm_Children). - Dialect closure: the YAML subset is declared not externally producible, so third-party tooling has no conformance target (UnityYAML manual page).
- Prerequisite: none of this works unless Force Text is enabled and the merge driver is installed per version control system (Editor settings; “Smart merge” manual page).
NUIF relevance
Borrow
- Sparse override sets addressed by
(target identity, property path)with separate structural add/remove lists; this is the minimal information needed to keep an instance non-destructive and matches NUIF’sapply instance overrideoperation. - Identity-keyed set merge for child and override lists, with explicit exclusion and tolerance rules declared in a rules file; NUIF’s three-way merge can express the same as typed merge policies per relation kind.
- Force-text plus one-line references as a canonicalization concern: NUIF’s
nuif-text-0profile should define a deterministic serialization precisely so that merge tools see only semantic change.
Adapt
- Replace file-local
int64identity with NUIF’s stable semantic entity IDs so that the same entity is addressable across component definitions, variants and documents; Unity’s failure class 1 disappears when override targets are semantic IDs rather than (asset GUID, local ID) pairs. - Encode containment once (ordered relation or fractional index) and derive parent pointers, so that merge cannot produce disagreeing parent/child encodings.
- Make override ordering canonical by a total order over
(target id, property key)defined in the spec, eliminating failure class 3. - Represent placeholder (“stripped”) objects as explicit correspondence records in the provenance layer instead of pseudo-entities in the containment tree.
Reject
- A merge tool that is separate from the document model and driven by path-pattern rules; NUIF merge must be defined over typed operations and relations (spec/06) so that structural invariants (acyclic containment, target existence) are checked during merge.
- Treating root transform properties as implicitly instance-local; NUIF should make every instance-level deviation an explicit override with fidelity accounting.
- A closed serialization dialect that third parties may not produce; NUIF serialization profiles are normative and externally implementable.
Open questions
- How
UnityYAMLMergematches objects when the samefileIDis created independently on both branches (collision on newly added objects); no primary source retrieved describes the generation algorithm for local IDs. - Whether the hybrid heuristic for unlisted arrays is stable across Unity versions; the manual does not specify it.
- Whether structural overrides (
m_RemovedGameObjects, introduced later than property overrides) interact correctly withsetmatching inmergerules.txt, whose default only listsm_Modifications.