BPVM Snack Pack #6 - The CDO Mystery: Your Class's Secret Template
Every Blueprint class has a hidden template object that nobody talks about. Meet the CDO - the mysterious instance that defines what 'default' really means.
The content in this post is based on Unreal Engine 5.6.0
BPVM Snack Pack - Quick Blueprint knowledge drops! Part of the Blueprint to Bytecode series.
The Mystery Object
You’ve created a Blueprint class. You haven’t spawned any instances yet. But surprise - an instance already exists.
It’s called the Class Default Object (CDO), and it’s been quietly living in memory since your class was loaded.
What Is a CDO?
Think of the CDO as the master mold for your class:
1
2
3
4
5
// When you create BP_MyActor...
UClass* MyClass = BP_MyActor::StaticClass();
// This already exists!
AActor* CDO = MyClass->GetDefaultObject(); // The secret instance
The CDO is:
- A real instance of your class (it’s an actual object in memory!)
- Created automatically when the class loads
- Never spawned in the world (it exists in limbo)
- The template for all future instances
Why Does Every Class Need One?
Problem: When you spawn an actor, where do its default values come from?
Bad Solution: Store defaults as metadata somewhere
1
2
3
4
5
6
// Imaginary bad design
class ClassMetadata {
float DefaultHealth = 100;
FString DefaultName = "Player";
// Hundreds of properties...
};
Unreal’s Solution: Just create one “perfect” instance and copy from it!
1
2
3
4
5
6
7
// The CDO IS the defaults
AActor* CDO = GetDefault<AActor>();
CDO->Health = 100; // Set once
CDO->Name = "Player";
// Spawning copies from CDO
AActor* NewActor = SpawnActor(); // Copies all properties from CDO
The Magic Moment
When you edit “Default” values in the Blueprint editor:
You’re not editing metadata. You’re editing the CDO directly!
1
2
3
4
5
// In Blueprint Editor, when you set Health = 100
CDO->Health = 100; // You're literally setting a property on the CDO
// Later, when spawning
NewInstance->Health = CDO->Health; // Copy from CDO
CDO in Action
Here’s the lifecycle:
1. Class Creation
1
2
3
4
5
// Blueprint gets compiled
UBlueprintGeneratedClass* NewClass = CompileBlueprint();
// CDO is created immediately
UObject* CDO = NewClass->GetDefaultObject();
2. Setting Defaults
1
2
3
4
// You edit in Blueprint editor
CDO->MaxHealth = 150;
CDO->TeamColor = FColor::Red;
CDO->WeaponClass = AK47::StaticClass();
3. Instance Creation
1
2
3
4
5
6
7
// Player spawns your actor
AActor* Instance = World->SpawnActor<AActor>(BP_MyActor);
// Under the hood:
// 1. Allocate memory
// 2. Copy all properties from CDO
// 3. Run constructor
The Revert Button Mystery
Ever wondered how the “Revert to Default” button works?
![Property with revert button in editor]
It’s just comparing to the CDO:
1
2
3
4
5
6
bool IsModified = (Instance->Health != CDO->Health);
// If true, show yellow revert button
void RevertToDefault() {
Instance->Health = CDO->Health; // Just copy from CDO!
}
CDO vs Constructor Defaults
C++ Constructor:
1
2
3
AMyActor::AMyActor() {
Health = 100; // Runs EVERY spawn
}
CDO System:
1
2
3
4
5
// Set once on CDO
CDO->Health = 100;
// Spawning just copies memory (faster!)
memcpy(NewInstance, CDO, sizeof(AActor));
The CDO approach is much faster for spawning many instances!
The Hidden CDO Lifecycle
During Compilation:
1
2
3
4
5
6
7
8
9
10
11
12
13
void CompileBlueprint() {
// Old CDO still has player's configured defaults
UObject* OldCDO = OldClass->GetDefaultObject();
// Clean the class
CleanAndSanitizeClass(OldClass);
// Recompile everything
CompileClass(NewClass);
// Copy defaults from old CDO to new CDO!
CopyPropertiesFrom(OldCDO, NewCDO);
}
This is why your default values survive recompilation!
CDO Gotchas
1. CDO Exists in Editor AND Runtime
1
2
3
4
5
// In editor
CDO->SomeProperty = 10; // Editing defaults
// In packaged game
CDO->SomeProperty; // Still 10! (read-only now)
2. Never Modify CDO at Runtime
1
2
// DON'T DO THIS in gameplay code!
CDO->Health = 200; // You just changed defaults for ALL future spawns!
3. CDO and Hot Reload
1
2
3
4
// During hot reload
OldCDO->SaveDefaults();
RecompileClass();
NewCDO->RestoreDefaults(); // Your settings survived!
Quick Takeaway
- Every class has a CDO (Class Default Object) - a hidden template instance
- When you edit defaults in Blueprint, you’re editing the CDO
- Spawning actors copies properties from the CDO (fast!)
- The CDO survives recompilation (that’s why defaults persist)
- Never modify the CDO at runtime (it affects all future spawns)
The CDO Is Everywhere
Next time you:
- Set a default value in Blueprint
- Hit the revert button
- Spawn an actor
- Recompile a Blueprint
Remember: You’re interacting with the CDO, the secret template object that makes Unreal’s class system work!
Want More Details?
For the complete explanation with code:
Next up: How node handlers turn your graph into code!
🍿 BPVM Snack Pack Series
- ← #5: SuperStruct Magic
- #6: The CDO Mystery ← You are here
- #7: Node Handlers Explained →
