This page provides an overview of Godot's resource system: the data model, loading pipeline, caching, file formats, import system, and saving pipeline. It is intended as a map of how these subsystems connect.
Detailed treatment of each subsystem is in the child pages:
ResourceLoader singleton and threaded loading, see ResourceLoaderResource base class, see Resource ClassResourceSaver singleton and savers, see ResourceSaverA resource is a reference-counted, serializable data object. Every resource:
Resource (core/io/resource.h53-194)RefCounted, so it is freed automatically when all references drop to zeroresource_path (e.g., res://my_sprite.png) that uniquely identifies it in the global cachechanged signal when its data changesResources are the primary unit of data interchange in Godot: textures, meshes, animations, materials, scripts, and packed scenes are all resources.
Sources: core/io/resource.h53-194 doc/classes/Resource.xml1-198
System Architecture Diagram
Sources: core/io/resource_loader.h47-311 core/io/resource_saver.h36-56 core/io/resource.h53-216 core/io/resource_importer.h41-107 core/io/resource_format_binary.h38-195 scene/resources/resource_format_text.h40-175
Resource (core/io/resource.h53-194) is the base class for all Godot resources. Key fields and behaviors:
| Member | Type | Purpose |
|---|---|---|
path_cache | String | Canonical res:// path; key into ResourceCache |
scene_unique_id | String | ID within a .tscn or .scn file (e.g., AbCd1) |
name | String | Optional human-readable label |
local_to_scene | bool | If true, resource is duplicated per scene instance |
local_scene | Node* | Scene root when local_to_scene is true |
Resource::set_path() (core/io/resource.cpp71-108) atomically:
ResourceCache::resourcesResourceCache::resourcesResource::set_path_cache() (core/io/resource.cpp114-117) sets path_cache without touching the cache — used when cache mode is CACHE_MODE_IGNORE.
A resource is "built-in" (embedded in another file) when is_built_in() returns true. This happens when the path is empty, contains ::, or starts with local://. Sub-resources in a .tscn file have paths like res://scene.tscn::AbCd1.
Resource::duplicate() (core/io/resource.cpp509-528) performs a shallow or deep copy:
p_deep = true): recursively duplicates internal (built-in) sub-resources.duplicate_deep() (core/io/resource.cpp530-551): extends deep copy control with ResourceDeepDuplicateMode — NONE, INTERNAL, or ALL.A thread-local remap cache (thread_duplicate_remap_cache) ensures that diamond-shaped resource graphs produce only one copy of each shared resource.
Resource::emit_changed() (core/io/resource.cpp41-52) emits the changed signal. During threaded loading, it queues the emit through ResourceLoader::resource_changed_emit() instead of calling it directly.
Sources: core/io/resource.cpp41-268 core/io/resource.h53-216
ResourceCache (core/io/resource.h198-216) is a static class holding a HashMap<String, Resource*> of all currently live resources, keyed by their res:// paths.
Key methods:
| Method | Behavior |
|---|---|
ResourceCache::has(path) | Returns true if the path is currently cached |
ResourceCache::get_ref(path) | Returns a Ref<Resource> to the cached resource; may return null if the resource is being destroyed |
Access to the map is protected by ResourceCache::lock (a Mutex). ResourceLoader also holds a reference to this lock for coordinated atomic check-and-insert operations.
Sources: core/io/resource.h198-216 core/io/resource.cpp71-108
ResourceLoader (core/io/resource_loader.h105-311) is a static singleton that routes load requests to registered ResourceFormatLoader instances.
Loaders are stored in a fixed-size array loader[MAX_LOADERS] (64 slots). They are registered with:
ResourceLoader::add_resource_format_loader(loader, at_front)
ResourceLoader::_load() (core/io/resource_loader.cpp273-331) iterates the registered loaders in order and calls loader[i]->recognize_path(path, type_hint). The first loader that recognizes the path and succeeds is used.
ResourceFormatLoader::CacheMode controls whether existing cache entries are used or replaced:
| Mode | Behavior |
|---|---|
CACHE_MODE_IGNORE | Neither the main resource nor its sub-resources use the cache |
CACHE_MODE_REUSE | Cache entries are used if present (default) |
CACHE_MODE_REPLACE | Existing cached resource data is refreshed from disk |
CACHE_MODE_IGNORE_DEEP | IGNORE propagated recursively to dependencies |
CACHE_MODE_REPLACE_DEEP | REPLACE propagated recursively to dependencies |
ResourceLoader has a full threaded-load infrastructure (core/io/resource_loader.h176-226):
load_threaded_request(path) — starts a background load task via WorkerThreadPoolload_threaded_get_status(path) — polls THREAD_LOAD_IN_PROGRESS, THREAD_LOAD_LOADED, or THREAD_LOAD_FAILEDload_threaded_get(path) — blocks until complete and returns the resultEach task is represented by a ThreadLoadTask struct and a LoadToken ref-counted handle. Multiple callers requesting the same path share the same ThreadLoadTask.
Sources: core/io/resource_loader.h105-311 core/io/resource_loader.cpp273-534
ResourceFormatLoader (core/io/resource_loader.h47-95) is the abstract interface that format-specific loaders implement.
ResourceFormatLoader virtual method table
All virtual methods are GDVirtual, making it possible to implement custom loaders in GDScript or C++ equally.
Sources: core/io/resource_loader.h47-95 core/io/resource_loader.cpp60-221
Godot uses two primary serialization formats:
.tres / .tscn)Handled by ResourceLoaderText and ResourceFormatLoaderText (scene/resources/resource_format_text.h scene/resources/resource_format_text.cpp).
A .tres file has sections:
[gd_resource type="SomeResource" format=4]
[ext_resource type="Texture2D" uid="..." path="res://tex.png" id="1"]
[sub_resource type="ShaderMaterial" id="mat_abc"]
albedo_color = Color(1, 0, 0, 1)
[resource]
material = SubResource("mat_abc")
The loader parses ext_resource tags first and starts background loads for each dependency via ResourceLoader::_load_start(). Then sub_resource blocks are parsed in order, building an int_resources map. The final [resource] or [node] section fills in the main resource.
A .tscn (scene) file uses [node] tags parsed by _parse_node_tag() into a PackedScene.
Format versions:
| Version | Notes |
|---|---|
| 1 | Original |
| 2 | Renamed types (Basis, AABB, etc.) |
| 3 | String IDs for sub/ext resources |
| 4 | PackedByteArray base64, PackedVector4Array |
.res / .scn)Handled by ResourceLoaderBinary and ResourceFormatLoaderBinary (core/io/resource_format_binary.h core/io/resource_format_binary.cpp).
The binary format is a structured byte stream: a header with magic bytes, format version, string table, external resource list, internal resource list (with byte offsets), and property data. Each resource's properties are encoded using a fixed-tag type system (VARIANT_INT, VARIANT_OBJECT, OBJECT_EXTERNAL_RESOURCE_INDEX, etc.).
Binary format versions:
| Version | Notes |
|---|---|
| 1 | Original |
| 2 | 64-bit float/int support |
| 3 | NodePath encoding changed |
| 4 | String IDs for ext/sub resources |
| 5 | Script class in header |
| 6 | PackedVector4Array type |
Sources: scene/resources/resource_format_text.cpp451-908 core/io/resource_format_binary.cpp681-808 core/io/resource_format_binary.h38-107
ResourceFormatImporter (core/io/resource_importer.h41-107) is itself a ResourceFormatLoader. When the engine loads a file like res://texture.png, this loader:
.import file (res://texture.png.import)path, type, uid, and importer fields.godot/imported/This means the asset pipeline is transparent to the rest of the engine — callers use the original path, and the importer silently resolves to the imported artifact.
ResourceImporter (core/io/resource_importer.h109-158) is the base class for the actual converters (e.g., ResourceImporterTexture, ResourceImporterOggVorbis). Each importer declares:
get_recognized_extensions() — source file extensions it handlesget_resource_type() — target resource class nameimport() — the conversion logicSources: core/io/resource_importer.h41-158 core/io/resource_importer.cpp44-200
ResourceSaver (core/io/resource_saver.h core/io/resource_saver.cpp) is the static singleton for writing resources to disk.
ResourceSaver::save(resource, path, flags) (core/io/resource_saver.cpp102-155) iterates registered ResourceFormatSaver instances. For each one it calls:
saver->recognize(resource) — does this saver handle this resource type?saver->recognize_path(resource, path) — does it handle this file extension?The first matching saver's save() is called.
| Flag | Effect |
|---|---|
FLAG_RELATIVE_PATHS | Store dependency paths relative to the file |
FLAG_BUNDLE_RESOURCES | Embed sub-resources instead of referencing them |
FLAG_CHANGE_PATH | Update the resource's resource_path after saving |
FLAG_OMIT_EDITOR_PROPERTIES | Skip editor-only properties |
FLAG_COMPRESS | Enable compression |
ResourceFormatSaver (core/io/resource_saver.h36-56) exposes:
| Virtual Method | Purpose |
|---|---|
_save(resource, path, flags) | Perform the actual file write |
_recognize(resource) | Return true if this saver handles the resource type |
_get_recognized_extensions(resource) | Return list of file extensions |
_recognize_path(resource, path) | Override extension matching |
_set_uid(path, uid) | Write a UID association for the file |
Sources: core/io/resource_saver.cpp46-155 core/io/resource_saver.h36-95
Diagram: ResourceLoader.load() call path
Sources: core/io/resource_loader.cpp273-534 core/io/resource_loader.cpp536-640
Resources can be identified by a stable numeric UID independent of their file path, managed by the ResourceUID singleton. UIDs are stored:
.uid file next to the resource (for non-imported resources without custom UID support).import file for imported resources[ext_resource uid="uid://..."] header field of text filesResourceLoader::_validate_local_path() (core/io/resource_loader.cpp475-484) resolves a uid://... path to a real res:// path before loading begins.
Sources: core/io/resource_loader.cpp475-484 core/io/resource_loader.h250-255 scene/resources/resource_format_text.cpp490-506
Both loaders and savers can be added at runtime:
ResourceLoader::add_resource_format_loader(loader, at_front) — registers a new ResourceFormatLoaderResourceSaver::add_resource_format_saver(saver, at_front) — registers a new ResourceFormatSaverIn GDScript, a class that extends ResourceFormatLoader and has a class_name is auto-registered on startup. The same applies to ResourceFormatSaver.
For importing external asset types, ResourceImporter is the appropriate extension point (see Resource Import System).
Sources: core/io/resource_loader.h248-249 doc/classes/ResourceFormatLoader.xml7-9 doc/classes/ResourceFormatSaver.xml7-9
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.