This page documents the ResourceSaver singleton and the ResourceFormatSaver interface, which together handle persisting Resource objects to disk. The saver side is the write counterpart to the loader side; for documentation on how resources are read from disk see ResourceLoader, and for the resource caching system see Resource Cache.
ResourceSaver is a static singleton that maintains an ordered list of ResourceFormatSaver plugins. When a save is requested, ResourceSaver iterates through the list and delegates to the first registered saver that accepts the resource type and path. Individual ResourceFormatSaver subclasses implement the actual serialization—either as human-readable text (.tres, .tscn) or as compact binary (.res, .scn).
Architecture: ResourceSaver and its format savers
Sources: core/io/resource_saver.h core/io/resource_saver.cpp scene/resources/resource_format_text.h core/io/resource_format_binary.h
ResourceSaver is defined in core/io/resource_saver.h and implemented in core/io/resource_saver.cpp It is a pure static class (not a Godot Object singleton, but exposed to scripting through a wrapper).
The class holds an internal fixed-size array:
Savers are registered and removed with:
| Method | Description |
|---|---|
add_resource_format_saver(saver, at_front) | Appends or prepends a ResourceFormatSaver to the registry |
remove_resource_format_saver(saver) | Removes a previously registered saver |
add_custom_savers() | Loads savers defined in GDScript (called on engine startup) |
remove_custom_savers() | Unloads script-defined savers |
If at_front is true, the saver is inserted at position 0, giving it priority over any existing savers. The order matters because save() stops at the first matching saver.
Sources: core/io/resource_saver.h59-100 core/io/resource_saver.cpp39-44
save() FunctionBehavior:
p_path is empty, the resource's own resource_path is used.saver[i]->recognize(p_resource) — checks if the saver handles this resource type.saver[i]->recognize_path(p_resource, path) — checks if the saver handles this file extension.saver[i]->save(p_resource, path, p_flags) is called.set_edited(false) and (if timestamp_on_save) set_last_modified_time() are called on the resource.save_callback function pointer is invoked for res:// paths (used by the editor to update the filesystem).FLAG_CHANGE_PATH is set, the resource's resource_path is updated to the localized path.Sources: core/io/resource_saver.cpp102-190
Flags are defined as a bitfield enum ResourceSaver::SaverFlags:
| Flag constant | Value | Effect |
|---|---|---|
FLAG_NONE | 0 | No special behavior |
FLAG_RELATIVE_PATHS | 1 | Sub-resource paths are written relative to the scene that uses them |
FLAG_BUNDLE_RESOURCES | 2 | Sub-resources are embedded into the file rather than saved separately |
FLAG_CHANGE_PATH | 4 | Updates resource_path on the resource object after a successful save |
FLAG_OMIT_EDITOR_PROPERTIES | 8 | Skips properties that are editor-only |
FLAG_SAVE_BIG_ENDIAN | 16 | Binary format writes big-endian byte order |
FLAG_COMPRESS | 32 | Binary format enables file compression |
FLAG_REPLACE_SUBRESOURCE_PATHS | 64 | When saving, take over any conflicting sub-resource paths |
Sources: core/io/resource_saver.h64-74 doc/classes/ResourceSaver.xml67-100
| Method | Description |
|---|---|
get_recognized_extensions(resource, extensions) | Fills a list with all file extensions that any registered saver handles for the given resource |
set_uid(path, uid) | Iterates savers and calls set_uid() on the first one that succeeds |
get_resource_id_for_path(path, generate) | Returns the ResourceUID::ID for a file path via the save_get_id_for_path callback; generates a new ID if generate is true |
set_save_callback(callback) | Registers a ResourceSavedCallback function pointer invoked after each successful save |
set_get_resource_id_for_path(callback) | Registers a callback for UID lookup/generation (set by the editor) |
Sources: core/io/resource_saver.h76-100 core/io/resource_saver.cpp175-250
ResourceFormatSaver is the abstract plugin class. It inherits RefCounted, so instances are managed by reference counting. Concrete implementations override a set of GDVIRTUAL methods.
Class structure
Sources: core/io/resource_saver.h36-56 scene/resources/resource_format_text.h core/io/resource_format_binary.h
| Method | Signature | Description |
|---|---|---|
_save | (resource, path, flags) -> Error | Required. Serializes the resource to path. |
_set_uid | (path, uid) -> Error | Updates the UID record for the file at path. Default returns ERR_FILE_UNRECOGNIZED. |
_recognize | (resource) -> bool | Returns true if this saver can handle the given resource object. |
_get_recognized_extensions | (resource) -> PackedStringArray | Returns the file extensions this saver can write for the given resource. |
_recognize_path | (resource, path) -> bool | Returns true if this saver should handle the given path. If not overridden, the default checks the path extension against _get_recognized_extensions. |
Sources: core/io/resource_saver.h42-55 core/io/resource_saver.cpp46-100 doc/classes/ResourceFormatSaver.xml
The non-virtual public methods (save, recognize, etc.) dispatch through the GDVIRTUAL_CALL macro, which supports both C++ subclasses and GDScript overrides.
.tres / .tscnResourceFormatSaverText (scene/resources/resource_format_text.h)ResourceSaverTextInstance (scene/resources/resource_format_text.h).tres (generic resources) and .tscn (packed scenes)ResourceSaverTextInstance walks the resource graph and writes a structured text file containing:
[gd_resource] or [gd_scene] header with format version and type info[ext_resource] sections for referenced external resources[sub_resource] sections for embedded sub-resources[resource] section (or [node] sections for scenes) with property assignmentsThis format is human-readable, diff-friendly, and is the default format used by the Godot editor for project files.
Sources: scene/resources/resource_format_text.h130-200 scene/resources/resource_format_text.cpp
.res / .scnResourceFormatSaverBinary (core/io/resource_format_binary.h)ResourceFormatSaverBinaryInstance (core/io/resource_format_binary.h126-180).res (generic resources) and .scn (packed scenes)ResourceFormatSaverBinaryInstance writes a compact binary file. It:
Variant values in a compact binary type-tagged formatFLAG_SAVE_BIG_ENDIAN) and compression (FLAG_COMPRESS)The binary format is faster to load at runtime and produces smaller files, at the cost of not being human-editable. The current format version is 6 core/io/resource_format_binary.cpp98
Sources: core/io/resource_format_binary.h126-180 core/io/resource_format_binary.cpp44-101
Sequence: ResourceSaver.save() dispatching to a format saver
Sources: core/io/resource_saver.cpp102-190
A custom saver can be written in GDScript or C++:
In GDScript: Give the class a class_name that extends ResourceFormatSaver. Godot registers it automatically at startup via ResourceSaver::add_custom_savers(). Override the virtual methods prefixed with _.
In C++: Subclass ResourceFormatSaver, implement the virtual methods, and call ResourceSaver::add_resource_format_saver() during module initialization.
The key virtual methods to implement:
_recognize(resource) → bool # which resources you handle
_get_recognized_extensions(resource) → Array # which file extensions you write
_save(resource, path, flags) → Error # the actual serialization
Optionally implement _recognize_path if your path matching is more complex than extension comparison, and _set_uid if your format embeds UID data natively.
Sources: doc/classes/ResourceFormatSaver.xml core/io/resource_saver.h36-56
Every file saved in a Godot project may be assigned a ResourceUID::ID for stable cross-referencing. The saver system participates in two ways:
Native UID support: If a ResourceFormatSaver overrides _set_uid(), it stores the UID inside the file itself. The text format (ResourceFormatSaverText) does this by writing a uid= field in the file header.
Sidecar .uid file: For formats that do not override _set_uid(), the ResourceLoader reads a separate <filename>.uid file. ResourceSaver::set_uid() iterates all savers and falls through to the default ResourceFormatSaver::set_uid(), which returns ERR_FILE_UNRECOGNIZED, letting the engine write a plain .uid sidecar instead.
ResourceSaver::get_resource_id_for_path(path, generate) queries the editor-registered save_get_id_for_path callback to retrieve or create a UID for a path. This callback is only set in editor builds; at runtime the function returns ResourceUID::INVALID_ID unless generate is false.
Sources: core/io/resource_saver.h81-92 core/io/resource_saver.cpp165-200 doc/classes/ResourceSaver.xml29-64
The saver and loader systems are symmetric but independent. Both use the same plugin pattern (a registry of format handlers checked in order), and both use the same file extensions. The text format is handled by ResourceFormatSaverText / ResourceLoaderText, and the binary format by ResourceFormatSaverBinary / ResourceLoaderBinary. Neither the saver nor the loader directly communicate at runtime; they share only file paths and the resource cache (see Resource Cache).
Symbol mapping: Saver ↔ Loader counterparts
Sources: core/io/resource_saver.h core/io/resource_loader.h scene/resources/resource_format_text.h core/io/resource_format_binary.h
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.