After building dozens of games, here’s what I’ve learned: a save system isn’t just a technical feature—it’s a design choice that shapes how players experience your game. Get it wrong, and you’ll frustrate players. Get it right, and they’ll never think about it (which is exactly what you want).
This guide covers both the design philosophy and practical implementation of save systems, with code examples for multiple engines. Whether you’re building in Godot, Unity, or any other engine, these fundamentals apply.
Table of Contents
- Quick Answer
- Save System Types
- What to Save (And What Not To)
- Implementation Fundamentals
- File Formats: JSON vs Binary
- Common Mistakes to Avoid
- Pro Tips
- FAQ
Quick Answer
- Best approach for most games: Save to JSON files with periodic autosave every 2-5 minutes
- Store saves in the user’s documents/AppData folder—never in your game directory
- Save only what’s necessary: player state, progress flags, inventory, and world changes
- Always implement backup saves and corruption detection
- Test your save system early—retrofitting one later is painful
Save System Types
Before writing any code, decide which save system fits your game. Each type creates a different player experience:
1. Save Anywhere
Best for: Story-driven games, RPGs with long sessions, games where experimentation is encouraged.
Games like Divinity: Original Sin 2 let you save mid-combat. This removes tension but encourages wild experimentation—accidentally blow yourself up with explosive barrels? Just reload. The tradeoff is that challenge can feel meaningless when failure has no cost.
2. Checkpoint/Save Point Systems
Best for: Action games, platformers, survival horror, games built around tension.
Souls-like games and Resident Evil use save points as part of game design. The distance between safe zones creates tension—do you push forward or retreat? Placement is critical: too far apart and players get frustrated; too close and saves lose meaning.
Alien: Isolation takes this further—saving takes time, and enemies can still kill you while you’re saving. That design choice makes every save station a risk-reward decision.
3. Resource-Based Saving
Best for: Hardcore survival games, games where consequence matters.
Kingdom Come: Deliverance requires “Savior Schnapps” to save. This forces players to think strategically—save now, or save your precious items for later? Warning: This is polarizing. One of the most downloaded KCD mods removes this restriction entirely.
4. Autosave Only
Best for: Roguelikes, games designed around permadeath, mobile games.
The game saves automatically at key moments. Players can’t savescum their way through challenges. Works great for games where failure is part of the loop.
What to Save (And What Not To)
Save files should be as small as possible while capturing everything needed to restore the game state. Here’s how to think about it:
Always Save
- Player position and current scene/level
- Inventory and equipment
- Quest/story progress flags
- Stats, skills, and character data
- World state changes (opened chests, defeated bosses, unlocked doors)
- Settings preferences (often separate from game saves)
Don’t Save
- Anything that can be derived (calculated stats, derived values)
- Static data (item databases, enemy stats—these belong in your game files)
- Temporary state (current animation frame, particle effects)
- UI state (which menu is open, cursor position)
Pro tip: Save IDs and references, not full objects. Instead of saving an entire item’s data, save item_id: 47 and look up the item definition at load time.
Implementation Fundamentals
Regardless of engine, every save system follows the same pattern:
Step 1: Define Your Save Data Structure
Create a clear data structure that represents your game state. Keep it flat and serializable:
# Example structure (pseudocode)
SaveData:
version: "1.2" # Important for migration!
timestamp: "2026-01-26T12:00:00Z"
player:
position: {x: 100, y: 50}
health: 85
inventory: [47, 23, 12, 8] # Item IDs
world:
current_level: "dungeon_3"
flags: ["boss_1_defeated", "door_b_unlocked"]
chest_states: {chest_01: true, chest_02: false}
Step 2: Implement Serialization
Convert your game state to a saveable format. Here’s the Godot 4 approach:
extends Node
const SAVE_PATH = "user://savegame.json"
func save_game():
var save_data = {
"version": "1.0",
"timestamp": Time.get_datetime_string_from_system(),
"player": get_player_data(),
"world": get_world_data()
}
var file = FileAccess.open(SAVE_PATH, FileAccess.WRITE)
file.store_string(JSON.stringify(save_data, "\t"))
file.close()
print("Game saved!")
func load_game():
if not FileAccess.file_exists(SAVE_PATH):
print("No save file found")
return false
var file = FileAccess.open(SAVE_PATH, FileAccess.READ)
var json = JSON.new()
json.parse(file.get_as_text())
file.close()
var save_data = json.data
apply_player_data(save_data.player)
apply_world_data(save_data.world)
return true
Step 3: Handle the Save Location
Never save in your game’s installation directory. Use the platform-appropriate user directory:
- Godot:
user://(resolves to AppData on Windows, ~/Library on Mac) - Unity:
Application.persistentDataPath - Unreal:
FPaths::ProjectSavedDir()
File Formats: JSON vs Binary
Two main choices, each with tradeoffs:
JSON (Recommended for Most Games)
Pros:
- Human-readable—easy to debug
- Simple to implement
- Easy to migrate between versions
- Players can mod/edit saves if desired
Cons:
- Larger file sizes
- Easier for players to cheat
- Slower to parse (rarely matters)
Binary
Pros:
- Compact file sizes
- Fast to read/write
- Harder to edit (some security through obscurity)
- Can update partial sections without rewriting entire file
Cons:
- Harder to debug
- Version migration is tricky
- More complex implementation
Verdict: Use JSON unless you have a specific reason not to. The debugging benefits alone are worth the slightly larger file sizes.
Common Mistakes to Avoid
1. Adding Save Systems Late
Retrofitting a save system into an existing game is painful. Build your save system early, even if it only saves basic data. It’s much easier to expand a working system than to bolt one onto spaghetti code.
2. No Version Tracking
Your save format will change as you develop. Always include a version number so you can migrate old saves:
func load_game():
var data = parse_save_file()
match data.version:
"1.0":
data = migrate_v1_to_v2(data)
data = migrate_v2_to_v3(data)
"2.0":
data = migrate_v2_to_v3(data)
"3.0":
pass # Current version
apply_save_data(data)
3. No Backup System
Save files can corrupt. Keep at least one backup:
func save_game():
# Rotate backups
if FileAccess.file_exists("user://savegame.json"):
DirAccess.rename_absolute(
"user://savegame.json",
"user://savegame.backup.json"
)
# Write new save
write_save_file("user://savegame.json")
4. Saving References Instead of IDs
Never save object references or pointers. They won’t be valid after reload. Save identifiers and look up the objects when loading.
Pro Tips
- Add save slot screenshots—show players a preview of where they left off
- Implement autosave with visual feedback—a brief icon so players know their progress is safe
- Don’t autosave during boss fights—let players reload from before the encounter
- Test save/load constantly during development—you’ll catch issues early
- Consider cloud saves for Steam, consoles, or cross-platform play
- Add a “delete save” confirmation—and make it require actual effort (type “DELETE” or hold button)
- Store settings separately from game saves—players shouldn’t lose their keybinds when starting a new game
FAQ
Q: How often should autosave trigger?
A: Every 2-5 minutes for most games. More frequently for games with high-stakes moments. Always save after major events (boss kills, quest completion, item acquisition).
Q: Should I encrypt save files?
A: For single-player games, usually not worth the effort—players will find ways to edit saves anyway. For competitive or multiplayer games, server-side validation is more important than local encryption.
Q: How do I handle save corruption?
A: Always validate save data on load. Check for null values, out-of-range numbers, and missing required fields. Fall back to backup saves if validation fails.
Q: What about console certification?
A: Consoles have specific requirements for save data handling. PlayStation and Xbox require proper error handling, save size limits, and user confirmation for certain operations. Check platform documentation early.
Summary
A good save system is invisible—players save, load, and never think about the underlying complexity. Start simple with JSON saves, add versioning from day one, and expand as needed. Your future self (and your players) will thank you.
The best time to build your save system was at the start of your project. The second best time is now.
































































































































































































































