Contents
GuidePlatform

What Belongs In Save Data vs SlotInfo?

Decide what belongs in full game save data, what belongs in lightweight slotInfo, and how to keep save menus fast.

Every save system eventually separates two kinds of information:

  • the full state needed to resume the game
  • the small preview fields needed to show a save menu, character select screen, or support/debug summary

Persistly calls the full state save data. The lightweight preview object is slotInfo.

This article expands the save-model decision from One Save vs Multiple Save Slots. That guide helps you choose one autosave or multiple slots. This one focuses on what data belongs inside each layer once you have chosen the model.

The Short Rule

Put gameplay truth in save data.

Put preview labels and routing hints in slotInfo.

Save data answers:

Can the game resume correctly from this?

slotInfo answers:

Can the player or developer recognize this save without loading the whole payload?

What Belongs In Save Data

Save data should contain the facts your game needs to restore progress.

Good examples:

  • player level, XP, currency, and unlocked upgrades
  • checkpoint, area, wave, quest, and tutorial state
  • inventory, equipment, crafting state, and cooldowns
  • building positions, unlocked rooms, and persistent world state
  • schema version and migration markers

For a simple idle game, save data may look like this:

typescript
await PersistlyGameSaves.shared.saveData({
  schemaVersion: 1,
  level: 12,
  coins: 18420,
  checkpoint: "forest-gate",
  upgrades: {
    pickaxe: 4,
    backpack: 2,
  },
  lastTickAt: new Date().toISOString(),
});

This is the data the game needs after a refresh, crash, offline session, or device switch.

What Belongs In SlotInfo

slotInfo should stay small. It is for labels and preview fields, not the full save.

Good examples:

  • character name
  • class or build name
  • campaign name
  • level for display
  • last checkpoint label
  • thumbnail id
  • last played timestamp
typescript
await PersistlyGameSaves.shared.saveSlot("mage-main", gameState, {
  slotInfo: {
    characterName: "Astra",
    className: "Mage",
    level: 12,
    checkpointLabel: "Forest Gate",
    lastPlayedAt: new Date().toISOString(),
  },
});

When the game builds a save menu, it can list slots and show this preview data without loading every full save payload.

Why Not Put Everything In SlotInfo?

Because preview data tends to be read more often and shown in more places.

Keep it boring:

  • small
  • stable
  • non-sensitive
  • easy to render
  • safe to show in a menu

Do not use slotInfo for hidden economy state, anti-cheat decisions, private player notes, or large nested objects.

Why Not Put Everything In Save Data?

You can start that way for one-save games.

For a tiny game with only one autosave, saveData and loadData are enough. There may be no save menu and no need for preview metadata.

The moment you add manual slots, characters, campaigns, or "continue from this run" UI, slotInfo becomes useful because it avoids loading every full state just to draw a list.

Stable Slot IDs Are Not Display Names

A slot id should be stable. A display name can change.

Good slot ids:

  • autosave
  • campaign-1
  • character-main
  • challenge-hardcore

Bad slot ids:

  • Astra Level 12
  • Forest Gate 2026-06-15
  • New Save Copy Final

Use the stable id for API calls:

typescript
await PersistlyGameSaves.shared.saveSlot("character-main", state, {
  slotInfo: {
    characterName: "Astra",
    level: 12,
  },
});

Use slotInfo for the display label:

txt
Astra - Level 12

This keeps renames, localization, and UI polish from changing the save identity.

A Practical Split

Use this split as a starting point:

DataSave DataSlotInfo
Current coinsYesUsually no
Player levelYesOptional preview
Character nameOptionalYes
Inventory listYesNo
Equipped weapon nameYesOptional preview
Last played timeYesYes
Save schema versionYesNo
Menu thumbnail idOptionalYes

The same fact can appear in both places when it serves two different jobs. For example, level belongs in save data because gameplay needs it, and it may also appear in slotInfo because the menu wants to show it quickly.

Keep SlotInfo Backward-Compatible

Players may have old saves. Your save menu should tolerate missing preview fields.

typescript
const slots = await PersistlyGameSaves.shared.listSlots();

for (const slot of slots.slots) {
  const name = slot.slotInfo?.characterName ?? "Unnamed save";
  const level = slot.slotInfo?.level ?? "?";
  renderSaveRow(`${name} - Level ${level}`);
}

Avoid code that assumes every old slot has every new field.

What About Account-Level Data?

Some games also have data that belongs above one slot:

  • shared currency
  • account-wide unlocks
  • settings shared by characters
  • owned DLC flags
  • global tutorial state

Keep that separate from character or campaign slots. A character slot should not need to duplicate every account-wide fact.

For many games, the first version can ignore account-level data. Start with saveData or named slots, then add account-level structure when the game actually needs shared progress across slots.

Checklist

Use save data for:

  • gameplay state needed to resume
  • large or nested state
  • inventory, quests, upgrades, world state
  • migration/version fields

Use slotInfo for:

  • save-menu labels
  • character/campaign preview fields
  • small routing hints
  • values that can be missing without breaking load

Avoid:

  • large payloads in slotInfo
  • secrets or private player data in preview fields
  • display names as slot ids
  • syncing every small UI change as a cloud write