The short answer
An autoload is a scene or script that Godot adds to the scene tree before your main scene and keeps alive while the game runs. Register one under Project → Project Settings → Globals → Autoload, and with Global Variable enabled you can reach it by name from any script. Use autoloads for state and services that truly span scenes, such as game progress, audio, or an event bus. Keep level-specific data in its level, and reset global state deliberately when a new game starts.
What is an autoload in Godot?
Godot instantiates every autoload at startup and adds it as a child of the root viewport, ahead of the main scene. It is an ordinary Node, so it runs _ready(), _process(), and signals like any other node, and it survives calls such as change_scene_to_file() because it is not part of the current scene.
To register one, open Project → Project Settings → Globals → Autoload, choose a .gd or .tscn file, give it a name in PascalCase, and keep Global Variable enabled. That name becomes a global identifier, so GameState.coins works in any script. Autoloads load in the order listed, top to bottom.
- 1
Create the script
Save res://autoload/game_state.gd extending Node.
- 2
Register it
Add it in Globals → Autoload with the name GameState and Global Variable enabled.
- 3
Use it anywhere
Read and call GameState from any script, and connect to its signals.
When should I use an autoload, and when should I not?
An autoload is the right tool when data or a service must outlive scene changes and be reachable from many unrelated places. It is the wrong tool when it only saves you from passing a reference, because hidden global access makes it harder to see which code changes what.
| Need | Autoload? | Better alternative when not |
|---|---|---|
| Score, coins, or unlocks that persist across levels | Yes | — |
| Music that keeps playing through scene changes | Yes | — |
| Game-wide events such as player_died or level_completed | Yes, as an event bus | — |
| Data used only by one level | No | Keep it on the level’s root node |
| Finding the player from an enemy | No | Use a group, an exported reference, or a signal |
| Pure helper functions | No | Use static functions in a class_name script |
How do I build a typed game-state autoload?
Keep the state typed, change it through methods, and announce changes with signals. Listeners then update themselves, and nothing outside the autoload writes its variables directly. The reset() method gives a new game a known starting point, because the autoload itself is never recreated between scenes.
extends Node
signal coins_changed(coins: int)
signal level_unlocked(level_id: StringName)
var coins: int = 0
var unlocked_levels: Array[StringName] = [&"level_1"]
func add_coins(amount: int) -> void:
if amount <= 0:
return
coins += amount
coins_changed.emit(coins)
func unlock_level(level_id: StringName) -> void:
if level_id in unlocked_levels:
return
unlocked_levels.append(level_id)
level_unlocked.emit(level_id)
func reset() -> void:
coins = 0
unlocked_levels = [&"level_1"]
coins_changed.emit(coins)extends Label
func _ready() -> void:
GameState.coins_changed.connect(_on_coins_changed)
_on_coins_changed(GameState.coins)
func _on_coins_changed(coins: int) -> void:
text = "Coins: %d" % coinsKeep in mind: The label renders the current value once in _ready(). A signal only reaches listeners that are already connected, so a HUD created mid-game would otherwise stay blank until the next change.
How do I build an event bus with an autoload?
An event bus is an autoload that only declares signals. Any node can emit a game-wide event without knowing who listens, and any node can listen without holding a reference to the emitter. Keep the list short and name events in the past tense, so each one reads as something that already happened.
Godot may flag bus signals as unused because the bus never emits them itself. That is expected for this pattern, and the @warning_ignore annotation silences it per signal.
extends Node
@warning_ignore("unused_signal")
signal player_died
@warning_ignore("unused_signal")
signal level_completed(level_id: StringName, time_seconds: float)extends Area2D
@export var level_id: StringName = &"level_1"
var _start_msec: int = 0
func _ready() -> void:
_start_msec = Time.get_ticks_msec()
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node2D) -> void:
if not body.is_in_group(&"player"):
return
var elapsed: float = (Time.get_ticks_msec() - _start_msec) / 1000.0
Events.level_completed.emit(level_id, elapsed)What are the common autoload mistakes?
- Give the autoload a different name from any class_name in the project; Godot reports an error when a class name hides an autoload singleton.
- Reset global state explicitly when a new game starts; changing scenes does not recreate autoloads.
- Do not keep references to nodes from a level after it is freed; check is_instance_valid() or clear the reference on exit.
- Order autoloads so each one is listed after anything it uses in _ready().
- Disconnect or let freed listeners disconnect naturally; avoid connecting the same callback twice when a scene reloads.
- Running a single scene with F6 still loads every autoload, so a test scene sees the same global state as the full game.
Keep in mind: When global state behaves unexpectedly, open the Remote scene tree while the game runs. Autoloads appear under root beside the current scene, which makes it easy to inspect their live values.
How can GDSense help with autoloads?
GDSense includes your autoload names and script paths in the project map it attaches to conversations, so answers call GameState or Events by their real names instead of inventing a manager that does not exist. Ask it to trace who reads and writes a piece of global state before you change it.
@file res://autoload/game_state.gd
Coins sometimes carry over after I choose New Game from the main menu.
Trace where coins are written and where reset() should be called.
Keep the coins_changed signal and the GameState name. Suggest the smallest fix and a test.