Tags: unity, save, load, json, serialization, playerprefs, binary, cloud-saves, game-dev Last updated: 2026-06-27

Save & Load Systems Cheatsheet

Quick Reference

MethodBest ForLimitations
PlayerPrefsTiny data, settingsNo nesting, strings only, not secure
JSON + FileMost games, human-readableNot binary-efficient
BinaryFormatterCompact savesDeprecated (security), .NET only
Odin SerializerComplex typesThird-party asset
Cloud SaveCross-device, backupRequires platform SDK

PlayerPrefs

# Save
PlayerPrefs.SetInt("Level", 5);
PlayerPrefs.SetFloat("Volume", 0.8f);
PlayerPrefs.SetString("Name", "Player1");
PlayerPrefs.Save();

# Load
int level = PlayerPrefs.GetInt("Level", 1);
float vol = PlayerPrefs.GetFloat("Volume", 1f);
string name = PlayerPrefs.GetString("Name", "");

if (PlayerPrefs.HasKey("Level")) { }

PlayerPrefs.DeleteKey("Level");
PlayerPrefs.DeleteAll();

PlayerPrefs Limitations

JSON Serialization

Simple SaveData Class

[System.Serializable]
public class SaveData {
    public int level;
    public float health;
    public Vector3 position;
    public List<string> inventory;
}

public void Save() {
    SaveData data = new SaveData {
        level = 5, health = 80f,
        position = player.position,
        inventory = new List<string> { "Sword", "Potion" }
    };

    string json = JsonUtility.ToJson(data, prettyPrint: true);
    File.WriteAllText(Application.persistentDataPath + "/save.json", json);
}

public SaveData Load() {
    string path = Application.persistentDataPath + "/save.json";
    if (File.Exists(path)) {
        string json = File.ReadAllText(path);
        return JsonUtility.FromJson<SaveData>(json);
    }
    return new SaveData();
}

JsonUtility Limitations

Newtonsoft.Json (for complex types)

using Newtonsoft.Json;

string json = JsonConvert.SerializeObject(data, Formatting.Indented,
    new JsonSerializerSettings {
        TypeNameHandling = TypeNameHandling.Auto,
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    });

SaveData data = JsonConvert.DeserializeObject<SaveData>(json, settings);

Binary Formatting (Legacy)

# ⚠ Deprecated due to security vulnerabilities.

using System.Runtime.Serialization.Formatters.Binary;

[System.Serializable]
public class SaveData { /* ... */ }

public void SaveBinary(SaveData data) {
    BinaryFormatter bf = new BinaryFormatter();
    using FileStream fs = File.Create(path);
    bf.Serialize(fs, data);
}

public SaveData LoadBinary() {
    BinaryFormatter bf = new BinaryFormatter();
    using FileStream fs = File.OpenRead(path);
    return (SaveData)bf.Deserialize(fs);
}

AES Encryption (Simple)

using System.Security.Cryptography;
using System.Text;

public static string Encrypt(string json, string password) {
    byte[] key = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(password));
    using Aes aes = Aes.Create();
    aes.Key = key;
    aes.GenerateIV();
    using ICryptoTransform encryptor = aes.CreateEncryptor();
    byte[] plainBytes = Encoding.UTF8.GetBytes(json);
    byte[] cipherBytes = encryptor.TransformFinalBlock(
        plainBytes, 0, plainBytes.Length);
    byte[] result = new byte[aes.IV.Length + cipherBytes.Length];
    Buffer.BlockCopy(aes.IV, 0, result, 0, aes.IV.Length);
    Buffer.BlockCopy(cipherBytes, 0, result, aes.IV.Length, cipherBytes.Length);
    return Convert.ToBase64String(result);
}

Save Slots & Multiple Saves

public void SaveToSlot(int slot) {
    SaveData data = GatherSaveData();
    string json = JsonUtility.ToJson(data);
    string path = $"{Application.persistentDataPath}/slot{slot}.json";
    File.WriteAllText(path, json);
}

public SaveData LoadFromSlot(int slot) {
    string path = $"{Application.persistentDataPath}/slot{slot}.json";
    return File.Exists(path)
        ? JsonUtility.FromJson<SaveData>(File.ReadAllText(path))
        : null;
}

Save Metadata (Timestamp, Thumbnail)

public class SaveSlotInfo {
    public int slot;
    public string timestamp;
    public string sceneName;
    public float playTime;
}

Auto-Save & Checkpoints

public float autoSaveInterval = 60f;
float timer;

void Update() {
    timer += Time.deltaTime;
    if (timer >= autoSaveInterval) {
        SaveToSlot(0);    # Auto-save slot
        timer = 0f;
    }
}

void OnTriggerEnter(Collider other) {
    if (other.CompareTag("Checkpoint"))
        SaveToSlot(1);    # Checkpoint slot
}

Cloud Saves

Unity Cloud Save

using Unity.Services.CloudSave;

await CloudSaveService.Instance.Data.Player.SaveAsync(
    new Dictionary<string, object> { { "SaveSlot1", json } });

var data = await CloudSaveService.Instance.Data.Player.LoadAsync(
    new HashSet<string> { "SaveSlot1" });

Save File Locations

PlatformPath
Windows / Mac / LinuxApplication.persistentDataPath
iOS / AndroidApplication.persistentDataPath
WebGLApplication.persistentDataPath (IndexedDB)
ConsolePlatform-specific, requires SDK

Best Practices

PracticeWhy
Version your save dataMigrate old saves when game updates
Validate on loadCheck for corrupted or tampered saves
Hash/checksum integrityDetect tampering for leaderboards
Async save/loadAvoid frame hitches during I/O
Backup before overwriteCopy old save to .bak before saving
Compress large savesGZip reduce JSON bloat ~10×
Encrypt sensitive dataPlayer currency, unlockables
Test save on all platformsPaths and permissions differ