AppleyAppley Docs
Docs/API Reference

Save Systems

Implement cloud-based save systems with versioning and serialization.

27 min read Intermediate Updated 2026-07-01 v2.0 ~95 min to complete

Introduction

Save systems persist game progress to the cloud. This guide covers save data structure, versioning, auto-save, and handling save data migrations.

Guide 16 of 25

This is part of the Intermediate Guides collection. Category: Gameplay Systems. Estimated completion: 95 minutes. Difficulty: Intermediate.

Screenshot

Save Systems
Save Systems

Step-by-Step Guide

1

Design save data structure

Define a save object with: player position, health, inventory, quest progress, settings, stats.

2

Version your save data

Include a version number. When structure changes, increment version and write a migration function.

3

Implement auto-save

Save at key moments: level complete, checkpoint, every 60 seconds, on game close.

4

Use async saves

Save asynchronously to avoid frame hitches. Show Saving... indicator while in flight.

5

Handle save corruption

Validate save data on load. If validation fails, fall back to previous save or start fresh.

6

Compress large saves

For large data (inventory, world state), compress before storing to reduce cloud costs.

FluxScript Example

Here is a complete FluxScript implementation for this guide:

Save Systems — FluxScript
const SAVE_VERSION = 3

func createSaveData() {
  return {
    version: SAVE_VERSION,
    timestamp: time.now(),
    player: { position: player.position, health: player.health, level: player.level },
    inventory: inventory.getItems(),
    quests: questSystem.getAllStates(),
    stats: { playTime: stats.playTime, kills: stats.kills }
  }
}

func saveGame() {
  data = createSaveData()
  ui.show("savingIndicator")
  save.set("gameSave", data)
  save.flush().then(() => {
    ui.hide("savingIndicator")
    ui.toast("Game saved")
  })
}

func loadGame() {
  data = save.get("gameSave")
  if data == null { print("New game"); return }
  if data.version < SAVE_VERSION {
    data = migrateSave(data, data.version)
  }
  player.health = data.player.health
  player.setPosition(data.player.position)
  inventory.loadItems(data.inventory)
  questSystem.loadStates(data.quests)
}

func migrateSave(data, fromVersion) {
  if fromVersion < 2 { data.player.shield = 0 }
  if fromVersion < 3 { data.equipment = {} }
  data.version = SAVE_VERSION
  return data
}

on timer("autoSave", 60) { saveGame() }

Node Graph Example

Prefer visual programming? Here is the equivalent Node Graph:

Save Systems — Node Graph
[Function: saveGame] --> [Create Save Data: version, player, inventory]
   --> [Show: savingIndicator] --> [Save + Flush async]
   --> [Hide indicator] --> [Toast: Game saved]

[Function: loadGame] --> [Save.Get] --> [Branch: null -> new game]
   --> [Branch: version < current] --> [Migrate]
   --> [Restore: player, inventory, quests, stats]

[Function: migrateSave] --> [If v<2: add shield]
   --> [If v<3: add equipment] --> [Update version]

[On Timer "autoSave" 60s] --> [saveGame]

Optimization Tips

Keep your implementation fast and efficient with these optimization tips:

  • Version your save data from day one. Include a version field and write migration functions when structure changes.
  • Save asynchronously. Cloud saves can take 100-500ms — sync saves cause visible frame freezes.
  • Compress large save data. Inventories with hundreds of items should be compressed before storage.
  • Keep multiple save slots. Store the last 3-5 saves so players can recover from corruption.

Common Mistakes

No save version field

Without a version, updating your game breaks all existing saves. Always include version + migration.

Saving synchronously

Sync saves cause frame freezes. Always use async saves with save.flush().