Autoloads are one of those Godot features that feel amazing for the first hour and dangerous by the second day. You make a script global, call it from anywhere, and suddenly half your project can talk to half your project. That can be useful. It can also become the quiet reason your prototype is hard to change.
The short version: use Godot Autoloads for systems that truly belong to the whole game. Use scenes, signals, and Resources for almost everything else. If you are still shaping your project layout, read the Godot project structure guide first, then come back here and decide which scripts deserve to be global.
What an Autoload Actually Does
An Autoload is a script or scene that Godot creates when your project starts. You register it in Project Settings, give it a name, and then access that name from anywhere in GDScript. Many developers call this a singleton because there is one shared instance.
# GameState.gd
extends Node
var coins: int = 0
var current_level: String = "level_01"
func add_coin(amount: int = 1) -> void:
coins += amount
func reset_run() -> void:
coins = 0
current_level = "level_01"After adding GameState.gd as an Autoload named GameState, any script can call GameState.add_coin(). That is convenient. The design question is whether every script should be allowed to know that global object exists.
Good Uses for Autoloads
The best Autoloads sit near the edge of your game. They coordinate things that outlive one scene and do not naturally belong to a single level object. They are not where every enemy stores its health.
- SaveManager: reads and writes save files, then gives scenes clean data.
- SceneLoader: handles level transitions, loading screens, and fade timing.
- AudioManager: owns music, bus volume, mute settings, and crossfades.
- Settings: stores resolution, input preferences, language, and accessibility options.
- GameSession: tracks run-wide state in a roguelike, match, or campaign session.
A good test is simple: if you reload the current level, should this object survive? Save data, audio, and settings usually should. A door, a coin, a temporary buff, or one enemy's state usually should not.
What Not to Put in a Singleton
Do not use an Autoload because you do not want to pass references, connect signals, or think about ownership. That shortcut feels fast until your UI, player, enemies, and save system all depend on the same global script.
Scene-local state should stay scene-local. Item definitions should often be Godot Resources. UI should react through signals instead of constantly polling a global script. Practice that separation in the Scene Builder if the boundary still feels fuzzy.
A Cleaner SaveManager Pattern
Save systems are a sensible Autoload use case because saving and loading often cross scene boundaries. The trick is to keep the manager boring. Let it serialize data. Do not let it become the owner of every gameplay rule.
# SaveManager.gd
extends Node
const SAVE_PATH := "user://save.json"
func save_game(data: Dictionary) -> void:
var file := FileAccess.open(SAVE_PATH, FileAccess.WRITE)
file.store_string(JSON.stringify(data))
func load_game() -> Dictionary:
if not FileAccess.file_exists(SAVE_PATH):
return {}
var file := FileAccess.open(SAVE_PATH, FileAccess.READ)
var parsed := JSON.parse_string(file.get_as_text())
return parsed if parsed is Dictionary else {}The level or player can decide what data to save. SaveManager only handles the file. For a longer walkthrough, pair this with the Save and Load guide.
A Practical Rule of Thumb
Before making a script global, ask three questions: does it survive scene changes, does more than one unrelated scene need it, and would passing it manually make the code noisier instead of clearer? If the answer is yes to all three, an Autoload is probably fine.
If not, use normal Godot structure. Build a small scene, expose clean properties, send a signal when something happens, and let the parent coordinate the result. That habit is slower for five minutes and faster for the rest of the project.
