Skip to main content

GDScript Runtime API

The SaveFlow autoload is the main GDScript runtime facade.

Use these calls from gameplay code, menu code, tests, or editor utilities.

The method names on this page are the stable GDScript surface for the 1.0 line.

Before choosing a method, keep the save model in mind:

  • slot_id is the stable player-facing playthrough identity
  • save_data() and save_slot() target the slot's main record
  • save_scene() targets a scene-qualified record
  • save_scope() targets a scene-and-scope-qualified record
  • direct record calls are for explicit project-owned domains

See Player Slots And Records for the full model.

Configuration

SaveFlow.configure(settings: SaveSettings) -> SaveResult
SaveFlow.configure_with(
save_root: String,
slot_index_file: String,
storage_format: int = 0,
pretty_json_in_editor: bool = true,
use_safe_write: bool = true,
keep_last_backup: bool = true,
auto_create_dirs: bool = true,
include_meta_in_slot_file: bool = true,
project_title: String = "",
game_version: String = "",
data_version: int = 1,
save_schema: String = "main",
enforce_save_schema_match: bool = true,
enforce_data_version_match: bool = true,
verify_scene_path_on_load: bool = true,
file_extension_json: String = "json",
file_extension_binary: String = "sav",
log_level: int = 2
) -> SaveResult
SaveFlow.get_settings() -> SaveSettings
SaveFlow.set_storage_format(mode: int) -> SaveResult
SaveFlow.get_storage_format() -> int

Prefer SaveFlow Settings for project defaults. Use configure_with() when a test scene or bootstrapper needs code-side setup.

Save And Load Payloads

SaveFlow.save_slot(slot_id: String, data: Variant, meta_patch: Dictionary = {}) -> SaveResult
SaveFlow.save_data(slot_id: String, data: Variant, meta_patch: Dictionary = {}) -> SaveResult
SaveFlow.load_slot(slot_id: String) -> SaveResult
SaveFlow.load_slot_data(slot_id: String) -> SaveResult
SaveFlow.load_data(slot_id: String) -> SaveResult
SaveFlow.load_slot_or_default(slot_id: String, default_data: Variant) -> SaveResult

Use these when you already own the whole payload. These calls operate on the slot's main record.

For scene-authored game state, prefer Scope or scene calls.

Record Calls

SaveFlow.save_record(
slot_id: String,
record_key: String,
data: Variant,
meta_patch: Dictionary = {},
record_kind: String = "custom",
extra_meta: Dictionary = {}
) -> SaveResult
SaveFlow.load_record(slot_id: String, record_key: String) -> SaveResult
SaveFlow.load_record_data(slot_id: String, record_key: String) -> SaveResult
SaveFlow.record_exists(slot_id: String, record_key: String) -> bool
SaveFlow.list_slot_records(slot_id: String) -> SaveResult

A record is one payload under a player slot.

Use direct record calls only when your project owns a named custom domain such as quest_log, world_state, or settings.

Scene and Scope workflows generate their own record keys. Prefer save_scene() or save_scope() for scene-authored data so scene path and scope identity stay consistent.

Scene Graph Calls

SaveFlow.save_scene(slot_id: String, root: Node, meta_patch: Dictionary = {}, group_name: String = "saveflow") -> SaveResult
SaveFlow.load_scene(slot_id: String, root: Node, strict: bool = false, group_name: String = "saveflow") -> SaveResult
SaveFlow.save_nodes(slot_id: String, root: Node, meta_patch: Dictionary = {}, group_name: String = "saveflow") -> SaveResult
SaveFlow.load_nodes(slot_id: String, root: Node, strict: bool = false, group_name: String = "saveflow") -> SaveResult
SaveFlow.inspect_scene(root: Node, group_name: String = "saveflow") -> SaveResult
SaveFlow.collect_nodes(root: Node, group_name: String = "saveflow") -> SaveResult
SaveFlow.apply_nodes(root: Node, saveables_data: Dictionary, strict: bool = false, group_name: String = "saveflow") -> SaveResult

Use scene calls when Sources are discovered from the scene tree/group.

Scene calls write and read a scene-qualified record under the provided slot_id. If a legacy main record exists and the scene record is missing, load_scene() falls back to the main record for upgrade compatibility.

strict controls whether missing payload/source situations should fail harder. Keep it false while iterating; use strict only when the project expects an exact graph shape.

Scope Calls

SaveFlow.save_scope(slot_id: String, scope_root: SaveFlowScope, meta_patch: Dictionary = {}) -> SaveResult
SaveFlow.load_scope(slot_id: String, scope_root: SaveFlowScope, strict: bool = false) -> SaveResult
SaveFlow.gather_scope(scope_root: SaveFlowScope, pipeline_control: SaveFlowPipelineControl = null) -> SaveResult
SaveFlow.apply_scope(scope_root: SaveFlowScope, scope_payload: Dictionary, strict: bool = false, pipeline_control: SaveFlowPipelineControl = null) -> SaveResult
SaveFlow.inspect_scope(scope_root: SaveFlowScope) -> SaveResult

These are the recommended calls for domain-based gameplay saves.

Scope calls write and read a scene-and-scope-qualified record under the provided slot_id. This lets two scenes use the same local scope_key without sharing one physical record by accident.

Example:

var metadata := slot_workflow.build_active_slot_metadata(
"Village Start",
"manual",
"Chapter 1",
"Forest Gate",
playtime_seconds
)
var result := SaveFlow.save_scope(slot_workflow.active_slot_id(), $RoomScope, metadata)

Slot Management

SaveFlow.delete_slot(slot_id: String) -> SaveResult
SaveFlow.copy_slot(from_slot: String, to_slot: String, overwrite: bool = false) -> SaveResult
SaveFlow.rename_slot(old_id: String, new_id: String, overwrite: bool = false) -> SaveResult
SaveFlow.list_slots() -> SaveResult
SaveFlow.read_slot_summary(slot_id: String) -> SaveResult
SaveFlow.list_slot_summaries() -> SaveResult
SaveFlow.read_slot_metadata(slot_id: String, target_metadata: SaveFlowSlotMetadata = null) -> SaveResult
SaveFlow.read_meta(slot_id: String) -> SaveResult
SaveFlow.write_meta(slot_id: String, meta_patch: Dictionary) -> SaveResult
SaveFlow.inspect_slot_storage(slot_id: String) -> SaveResult
SaveFlow.inspect_slot_compatibility(slot_id: String) -> SaveResult
SaveFlow.validate_slot(slot_id: String) -> SaveResult
SaveFlow.get_slot_path(slot_id: String) -> SaveResult
SaveFlow.slot_exists(slot_id: String) -> bool
SaveFlow.get_index_path() -> String

Use summary and metadata reads for save/load menus. Avoid loading full gameplay payloads just to draw a save card.

Use list_slot_records() for editor, QA, migration, or diagnostics tools that need to inspect every record under one slot. Player save menus should usually group by slot summary instead.

Metadata Builders

SaveFlow.build_slot_metadata_patch(...) -> Dictionary
SaveFlow.build_slot_metadata(...) -> SaveFlowSlotMetadata
SaveFlow.build_meta(slot_id: String, meta_patch: Dictionary = {}) -> Dictionary

For most game menus, SaveFlowSlotWorkflow.build_active_slot_metadata() is the friendlier entry point.

Current Data Helpers

SaveFlow.set_value(path: String, value: Variant) -> SaveResult
SaveFlow.get_value(path: String, default_value: Variant = null) -> SaveResult
SaveFlow.clear_current() -> SaveResult
SaveFlow.get_current_data() -> SaveResult
SaveFlow.save_current(slot_id: String, meta_patch: Dictionary = {}) -> SaveResult
SaveFlow.load_current(slot_id: String) -> SaveResult

These are lower-level helpers for projects that want a current in-memory data store. Most scene-authored workflows can ignore them.

Runtime Entity Helpers

SaveFlow.register_entity_factory(factory: SaveFlowEntityFactory) -> SaveResult
SaveFlow.unregister_entity_factory(factory: SaveFlowEntityFactory) -> SaveResult
SaveFlow.clear_entity_factories() -> SaveResult
SaveFlow.restore_entities(descriptors: Array, context: Dictionary = {}, strict: bool = false, options: Dictionary = {}) -> SaveResult

SaveFlowEntityCollectionSource normally handles factory registration for the standard scene-owned workflow.

Use these directly only when your project owns factory registration manually.

restore_entities() returns a structured report in SaveResult.data when it can continue, or in SaveResult.meta when strict restore fails. The report contains restored_count, spawned_count, created_count, reused_count, skipped_count, missing_types, failed_ids, entity_restore_issues, and first_issue.

Each entry in entity_restore_issues has a stable code. Use these codes for logs, tests, and in-game recovery paths:

  • INVALID_DESCRIPTOR
  • MISSING_TYPE_KEY
  • MISSING_PERSISTENT_ID
  • FACTORY_NOT_FOUND
  • EXISTING_ENTITY_NOT_FOUND
  • SPAWN_RETURNED_NULL
  • ENTITY_GRAPH_APPLY_FAILED

Each issue entry includes descriptor_index, code, message, persistent_id, and type_key. Entries that can report useful context also include details. The Entity Collection inspector and troubleshooting docs use the same stable next-action text for these codes through the 1.0 line.

Dev Save Helpers

SaveFlow.save_dev_named_entry(entry_name: String) -> SaveResult
SaveFlow.load_dev_named_entry(entry_name: String) -> SaveResult

These are for editor/development workflows. They return SAVE_MANAGER_EDITOR_ONLY in exported builds. Do not build shipped save menus around dev named entries.