Quick answer: Only [Export] fields/properties on a Godot.Resource survive saving and loading. Mark every field you want persisted — raw C# fields aren’t enough.

A custom Resource saves a config file, but on reload one field is back to its default. That field wasn’t marked [Export], so Godot didn’t serialize it.

Export Is Required for Persistence

public partial class EnemyConfig : Resource
{
    [Export] public int Hp { get; set; } = 100;
    [Export] public float Speed { get; set; } = 5.0f;

    // NOT serialized — no Export
    public Vector2 LastKnownPos;
}

Resources only serialize what they advertise to the editor — which means [Export] members. A plain field is invisible to the saver.

Backing Field vs Property

Auto-properties work; backing fields with a custom getter/setter also work as long as the property itself has [Export]. Apply the attribute to the property, not the backing field.

Collections Need Typed Wrappers

For lists/dictionaries, use Godot.Collections.Array<T> / Godot.Collections.Dictionary<K, V> with [Export]. Plain List<T> doesn’t serialize through the resource system.

Re-Save After Adding

An existing .tres saved before you added the new [Export] field has no value for it — it loads as the default. Re-save once after adding to bake the current values in.

Verifying

Save the resource, reload — every [Export] field round-trips. Non-exported fields stay at their defaults (as intended).

“Resources serialize Exports. No Export, no persistence — even on public fields.”

For purely runtime caches you don’t want saved, deliberately omit Export — it’s a feature, not a bug, once you know the rule.