Resources & Loading

Resource is a refcounted data container that can be saved to disk (.tres text / .res binary) and shared.

26.1 What a Resource is

Resource is a refcounted data container that can be saved to disk (.tres text / .res binary) and shared. Textures, meshes, audio, materials, scenes (PackedScene), fonts, and themes are all resources. Loaded resources are cached: loading the same path twice returns the same instance.

26.2 Custom resources

Create instances via *FileSystem → New Resource → ItemData*, edit them in the Inspector, and save as sword.tres.

Resources are a great way to make data-driven games: enemy stats, weapon definitions, dialogue, level configs.

# res://data/item_data.gd
class_name ItemData
extends Resource

@export var id: StringName
@export var display_name := ""
@export_multiline var description := ""
@export var icon: Texture2D
@export var price := 0
@export var stackable := true
@export_range(1, 999) var max_stack := 99
@export var item: ItemData            # assign sword.tres in the Inspector

func _ready() -> void:
	$Icon.texture = item.icon
	$Name.text = item.display_name

26.3 Shared vs unique

Because resources are shared, modifying item.price at runtime changes it for every user of that resource. Use:

or enable *Local to Scene* (resource_local_to_scene = true) so each scene instance gets its own copy.

var my_stats: CharacterStats = base_stats.duplicate()   # independent copy (duplicate(true) for sub-resources)

26.4 preload vs load

| | preload | load | |-|-----------|--------| | When | When the script loads | When the line executes | | Path | Constant string only | Any expression | | Use | Small, always-needed assets | Optional or dynamic assets |

const Bullet := preload("res://scenes/bullet.tscn")   # loaded at script compile/load time; path must be constant
var level := load("res://levels/level_%d.tscn" % n)   # loaded at runtime (blocking)
var tex := load("res://missing.png") as Texture2D      # null + error if missing
if ResourceLoader.exists("res://levels/level_9.tscn"):
	pass

26.5 Background (threaded) loading

const LEVEL := "res://levels/big_level.tscn"
@onready var bar: ProgressBar = $ProgressBar

func _ready() -> void:
	ResourceLoader.load_threaded_request(LEVEL)

func _process(_delta: float) -> void:
	var progress := []
	var status := ResourceLoader.load_threaded_get_status(LEVEL, progress)
	match status:
		ResourceLoader.THREAD_LOAD_IN_PROGRESS:
			bar.value = progress[0] * 100.0
		ResourceLoader.THREAD_LOAD_LOADED:
			var scene: PackedScene = ResourceLoader.load_threaded_get(LEVEL)
			get_tree().change_scene_to_packed(scene)
		ResourceLoader.THREAD_LOAD_FAILED, ResourceLoader.THREAD_LOAD_INVALID_RESOURCE:
			push_error("Failed to load " + LEVEL)
			set_process(false)

26.6 Saving resources

Security: .tres/.res files can embed scripts. Loading resource files that players can edit or download can execute arbitrary code. For save files that may be shared, prefer JSON/ConfigFile or store_var without objects.

var err := ResourceSaver.save(my_resource, "user://inventory.tres")
if err != OK:
	push_error("Save failed: %s" % error_string(err))