How to save and load a game in Godot 4: FileAccess

By Eduardo Orellana · Updated

Open the file with FileAccess.open("user://save.dat", FileAccess.WRITE), write your data with store_var(), and read it back with FileAccess.open(path, FileAccess.READ) and get_var(). Godot 3's File class is gone: File.new() fails to parse with Identifier "File" not declared in the current scope.

AppImage, x86_64. Ubuntu 22.04, Debian 12, Fedora 39 or newer.

Intel or AMD Chromebook, with Linux turned on.

Download for macOSDownload for Windows

What Godot is checking

Godot 4 replaced File with FileAccess, opened through a static open() that returns the file or null. The file closes when the last reference to it goes, at the end of the function here.

store_var() writes any Variant, a Dictionary of your game state included, in Godot's binary format, and get_var() reads it back with its types. Objects are not stored unless you allow it, which is safer for save files.

user:// is the per-user data folder Godot gives each project, writable in exported games, unlike res://.

Reproduce it

A Godot 3 save, in a Godot 4 project.

extends Node

func _ready():
	var file = File.new()
	file.open("user://save.dat", File.WRITE)
	file.store_var({"level": 3})
	file.close()

What Godot 4.7.2 prints

Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org

SCRIPT ERROR: Parse Error: Identifier "File" not declared in the current scope.
   at: GDScript::reload (res://answers/how-to-save-a-game-in-godot-4/repro.gd:4)
SCRIPT ERROR: Parse Error: Identifier "File" not declared in the current scope.
   at: GDScript::reload (res://answers/how-to-save-a-game-in-godot-4/repro.gd:5)
ERROR: Failed to load script "res://answers/how-to-save-a-game-in-godot-4/repro.gd" with error "Parse error".
   at: load (modules/gdscript/gdscript_resource_format.cpp:46)

Fix it

Save a Dictionary to user:// and load it back.

extends Node

const SAVE_PATH := "user://save.dat"

func save_game(state: Dictionary) -> void:
	var file := FileAccess.open(SAVE_PATH, FileAccess.WRITE)
	file.store_var(state)

func load_game() -> Dictionary:
	if not FileAccess.file_exists(SAVE_PATH):
		return {}
	var file := FileAccess.open(SAVE_PATH, FileAccess.READ)
	return file.get_var()

func _ready() -> void:
	save_game({"level": 3, "coins": 120, "position": Vector2(64, 32)})
	var state := load_game()
	print(state)
	print(typeof(state["position"]) == TYPE_VECTOR2)

What the fixed script prints

Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org

{ "level": 3, "coins": 120, "position": (64.0, 32.0) }
true

Saving as JSON instead

JSON is readable and editable by hand, but it has no Vector2 or int: every number comes back a float. Use JSON.stringify() to write and JSON.parse_string() to read, and convert the types yourself.

Saving Resources

A custom Resource with @export properties saves with ResourceSaver.save(res, "user://save.tres") and loads with load(). Loading a .tres can run scripts, so only load save files your game wrote.

Verified on Godot 4.7.2

Both scripts on this page were run headless on Godot 4.7.2 (4.7.2.stable.mono.official.ed1daf0bf) on 18 October 2026, and the output above is what Godot printed, unedited.

Where the check lives in Godot's source: [gdscript_analyzer.cpp line 4689, the message](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_analyzer.cpp#L4689), [FileAccess in the class reference](https://github.com/godotengine/godot/blob/4.7.2-stable/doc/classes/FileAccess.xml).

Questions

Where is user:// on Windows?
%APPDATA%\Godot\app_userdata\<project name>\ by default, or %APPDATA%\<project name>\ when the project sets a custom user dir. OS.get_user_data_dir() prints it.
Why did FileAccess.open() return null?
The path is not writable or the folder does not exist. FileAccess.get_open_error() says why.