JSON vs ConfigFile vs Resource in Godot 4 — which save format and when
Godot 4 gives you three sanctioned ways to write a save file, and the docs describe each one without ever telling you which to pick. So you pick the first one you read about, ship it, and discover the trade-off six months later when a player's Vector2 comes back as a Dictionary or an old save crashes the new build. Here's what each format actually costs. JSON: portable, readable, type-lossy…
Godot 4 offers three ways to save game data: JSON, ConfigFile, and Resource. The documentation outlines each format without specifying which to choose. Developers often pick the first format they encounter, only to encounter issues later.
JSON is portable and readable, like saving in other languages. The save function opens a FileAccess object in write mode, converts the Dictionary to a string using JSON.stringify(), and stores it in the file. The load_game function checks if the file exists, opens it in read mode, parses the string into a Dictionary, and returns it if it's a Dictionary.
However, JSON has limitations. Numbers are converted to floats, Dictionary keys become strings, and Vector2, Color, and similar types do not survive the save/load process. These types must be converted manually, which can be time-consuming.
ConfigFile stores Godot's types in an INI file format. The save_game function creates a ConfigFile object, sets values using set_value() with the appropriate section and key, and saves the file. The load_game function creates a ConfigFile object, loads the file, and retrieves values using get_value() with defaults for missing keys.
ConfigFile maintains Godot's types, but it's limited to two levels (sections and keys) and cannot store custom class instances. Additionally, loading resources from untrusted sources poses a security risk.
Resource files turn saves into typed, autocompleted classes. The SaveData class defines int, Vector2, and Array fields. The save_game function creates a SaveData object, sets its fields, and uses ResourceSaver to save it as a .tres file. The load_game function checks if the .tres file exists, loads it as a SaveData object, and returns it.
Resource files ensure int vs float compatibility and provide autocomplete, but they come with security and script-tie-in considerations. Loading resources from untrusted sources can lead to code execution, and renaming the class or moving the file can break old saves.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.