I often see people asking online how to load resources or scenes that are not already loaded by the main scene or the script you’re running. The first answer I see is dumping everything in an autoload.

This works and it’s fine. It’s a valid approach.

However you will always have whatever you put in your autoload in memory at all times, and maybe you don’t want that.

What I usually do, is defining a loader per type of resources or scene that I need to be shared across my codebase. Let’s say that I want one for all my items in my super duper RPG:

extends Resource
class_name Items

enum items_id { POTION, SWORD, SHIELD}

const paths = {
        items_id.POTION: "res://path/vers/potion.tscn",
        items_id.SWORD: "res://path/vers/sword.tscn",
        items_id.SHIELD: "res://path/vers/shield.tscn",
    }j

static func get_item(item_id: items_id) -> Item:
    return load(paths[item_id])

This way, if I need the sword wherever in my codebase, I only ever have to do:

get_item(Items.items_id.SWORD)

The big advantage here is that the enum will be the source of truth for the whole codebase. Used as a type hint, it will throw a warning if your input is incorrect, for example, if you removed an item. Used as an export, you can easily select it from a dropdown. Being just an int under the hood means you can put it in any save system (saving resources or as a JSON), or send it on the network for very little work.

I love enums.