FarmHeart

Save Systems · Data · Storage · 10 min read · October 8, 2026

Save and Load Systems for Browser Games

Save and load systems are a fundamental requirement for any game that lasts longer than a single session. Browser games have unique storage constraints — no file system access, limited local storage, and users who expect their progress to survive across devices. Here’s how to build robust save systems for the browser.

Storage Options

The browser gives you several places to persist data:

Save Data Structure

Design your save format before writing any save code. A good save structure:

const saveData = {
  version: 3,           // schema version for migrations
  timestamp: Date.now(),
  player: {
    name: "Farmer Jo",
    level: 12,
    xp: 4500,
    gold: 1200,
    inventory: [
      { id: "wheat_seed", qty: 50 },
      { id: "iron_hoe", qty: 1, durability: 87 }
    ]
  },
  world: {
    day: 45,
    season: "autumn",
    weather: "rain",
    plots: [
      { x: 3, y: 1, crop: "pumpkin", growth: 0.8 },
      { x: 4, y: 1, crop: "corn", growth: 1.0 }
    ]
  },
  settings: {
    musicVolume: 0.7,
    sfxVolume: 1.0,
    autoSave: true
  }
};

Versioning and Migration

Your save format will change as you add features. Without version handling, old saves break when players update:

function migrateSave(data) {
  if (data.version === 1) {
    // v1 -> v2: added inventory durability
    data.player.inventory.forEach(item => {
      if (item.durability === undefined) item.durability = 100;
    });
    data.version = 2;
  }
  if (data.version === 2) {
    // v2 -> v3: added weather system
    data.world.weather = data.world.weather || "clear";
    data.version = 3;
  }
  return data;
}

Always migrate forward, never backward. Chain migrations so a v1 save can reach v5 by passing through v2, v3, v4 sequentially.

Auto-Save Implementation

class AutoSaver {
  constructor(game, intervalMs = 60000) {
    this.game = game;
    this.interval = intervalMs;
    this.dirty = false;
    this.timer = null;
  }

  markDirty() { this.dirty = true; }

  start() {
    this.timer = setInterval(() => {
      if (this.dirty) {
        this.save();
        this.dirty = false;
      }
    }, this.interval);
    // Also save when the page is about to unload
    window.addEventListener('visibilitychange', () => {
      if (document.hidden && this.dirty) this.save();
    });
  }

  save() {
    const data = this.game.serialize();
    localStorage.setItem('farmheart_save', JSON.stringify(data));
  }
}

Multiple Save Slots

For games that support multiple saves:

Data Integrity

Export and Import

Let players export their save as a downloadable file and import it on another browser or device:

function exportSave() {
  const data = localStorage.getItem('farmheart_save');
  const blob = new Blob([data], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'farmheart-save.json';
  a.click();
  URL.revokeObjectURL(url);
}

function importSave(file) {
  const reader = new FileReader();
  reader.onload = (e) => {
    const data = JSON.parse(e.target.result);
    const migrated = migrateSave(data);
    localStorage.setItem('farmheart_save', JSON.stringify(migrated));
  };
  reader.readAsText(file);
}

Related Articles

Ready to Play?

Jump into FarmHeart — free, no download, runs in your browser.

Play FarmHeart