Godot Project Settings System: How Configuration Values Are Stored and Retrieved
The Godot project settings system is a thread-safe singleton that stores configuration values in an ordered map of VariantContainer structs, persisting them to either project.binary or project.godot files with automatic versioning and change tracking.
The project settings system in godotengine/godot serves as the central configuration manager for both the editor and exported games. Located in core/config/, this thread-safe singleton handles everything from rendering quality to input mappings, storing values in specialized containers that track defaults, modifications, and persistence flags.
Core Architecture of the Project Settings System
The Singleton Pattern and Global Access
At the heart of the system is the ProjectSettings singleton, accessible via ProjectSettings::get_singleton() defined in [core/config/project_settings.h at line 53](https://github.com/godotengine/godot/blob/master/core/config/project_settings.h#L53). This global entry point ensures that both engine core systems and GDScript code interact with the same configuration state throughout the application lifecycle.
The VariantContainer Storage Structure
All settings reside in an RBMap<StringName, VariantContainer> props container, where each key follows the "section/property" format (e.g., "rendering/quality/filters"). The VariantContainer struct defined at lines 74-82 stores:
variant: The current runtime value as aVariantinitial: The default value assigned when the setting was first registered- Ordering metadata for editor presentation
- Meta-flags including
persist,basic,internal, andrestart_if_changed
Change Tracking and Metadata
Beyond raw values, the system maintains auxiliary collections to manage state:
changed_settings: Tracks which keys were modified during the current framecustom_prop_info: HoldsPropertyInfofor editor tooling and validationfeature_overrides: Contains platform-specific overrides consulted byget_setting_with_override()
These structures enable the editor to highlight modified values and prompt for application restarts when critical graphics or window settings change.
How Configuration Values Are Stored and Loaded
File Format Hierarchy and Parsing
When Godot loads a project, it attempts to read the binary format first through _load_settings_binary() (lines 511-534), looking for project.binary optimized for speed. If unavailable or unreadable, it falls back to _load_settings_text() (lines 560-585) to parse the human-readable project.godot file. Both parsers populate the props map via set(), which internally delegates to _set().
The Storage Lifecycle and Persistence
When storing a value through set() or set_setting(), the engine checks if the key exists and whether the value differs from the current variant. If modified, _set() (lines 318-339) updates the VariantContainer, increments the global _version counter, and records the change. During save operations, save_custom() (lines 1232-1250) writes only properties where variant != initial (unless forcing a full dump), ordered by VariantContainer::order to maintain editor-friendly organization.
Versioning and Migration Strategy
The CONFIG_VERSION constant (currently 5 defined in [project_settings.h at line 60](https://github.com/godotengine/godot/blob/master/core/config/project_settings.h#L60)) guards compatibility between engine versions. When loading older files, _convert_to_last_version() (lines 622-644) automatically migrates data to the current format, ensuring projects remain compatible across engine updates.
Working with Project Settings in Code
GDScript Usage
# Access the singleton (GDScript automatically binds to the C++ class)
var settings = ProjectSettings.get_singleton()
# Read a configuration value with a fallback default
var fps_limit = settings.get_setting("application/run/fps_limit", 60)
# Modify a setting at runtime (e.g., enable v-sync)
settings.set_setting("display/window/vsync_mode", DisplayServer.VSYNC_ENABLED)
# Mark a setting as requiring restart when altered
ProjectSettings.set_restart_if_changed("rendering/renderer/quality", true)
# Check if any settings under a prefix changed this frame
if ProjectSettings.check_changed_settings_in_group("display/window/"):
print("Window settings were modified")
# Persist changes to disk
var err = ProjectSettings.save()
if err == OK:
print("Project saved successfully")
C++ Implementation
// Retrieve a value with default fallback (from project_settings.cpp)
Variant ProjectSettings::get_setting(const String &p_setting, const Variant &p_default) const {
if (has_setting(p_setting))
return get(p_setting);
else
return p_default;
}
// Store a value and trigger change tracking
void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) {
set(p_setting, p_value); // delegates to _set() internally
}
Both GDScript and C++ APIs ultimately invoke the internal _set() and _get() functions that manipulate the RBMap storage directly, as implemented in [core/config/project_settings.cpp](https://github.com/godotengine/godot/blob/master/core/config/project_settings.cpp).
Summary
- The project settings system uses a thread-safe singleton pattern accessible globally via
ProjectSettings::get_singleton()defined incore/config/project_settings.h - Values are stored in
RBMap<StringName, VariantContainer>, where each entry tracks both current and initial values alongside persistence and restart flags - Godot prioritizes
project.binaryfor loading speed, falling back to the text-basedproject.godotwhen necessary - Only modified properties (where
variant != initial) are written during save operations, ordered by theordermetadata to maintain editor-friendly organization - Configuration version 5 includes automatic migration logic via
_convert_to_last_version()for backward compatibility across engine updates
Frequently Asked Questions
Where does Godot store project settings on disk?
Godot stores project settings in either project.binary (a fast, versioned binary format) or project.godot (a human-readable text file) in the project root. According to the source code in [core/config/project_settings.cpp](https://github.com/godotengine/godot/blob/master/core/config/project_settings.cpp#L511), the engine attempts to load the binary version first for performance, falling back to the text file if the binary is missing or corrupted.
What is the difference between project.godot and project.binary?
The project.godot file uses an INI-style text format readable by humans and version control systems, while project.binary is an optimized binary representation that parses faster. As implemented in _load_settings_binary() and _load_settings_text(), both formats contain identical data, but the binary version includes a config_version header for automated migration checking.
How do I check if a setting has changed during runtime?
Use ProjectSettings.check_changed_settings_in_group() to query if any keys within a specific prefix (such as "display/window/") were modified during the current frame. Internally, this checks against the changed_settings set populated whenever _set() detects a value modification, as defined in the public members section of [project_settings.h](https://github.com/godotengine/godot/blob/master/core/config/project_settings.h#L50).
What happens when I modify a setting that requires a restart?
When a setting has the restart_if_changed flag enabled (configured via set_restart_if_changed()), the engine records this metadata in the VariantContainer struct. While the value updates immediately in the props map, the editor uses this flag to display restart notifications, and the change only takes full effect after the application restarts and reloads the configuration from disk.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →