As firmware evolves, stored settings formats change. If EEPROM layout is not versioned, upgrades can silently load garbage and produce hard-to-diagnose behavior.

My pattern is a small config header with magic bytes, schema version, payload length, and CRC. On boot, the firmware validates the header first. If validation fails, it loads defaults and writes a clean config block.

For each schema change, I add a migration function from version N to N+1. This makes upgrades explicit and testable.

The result is predictable: old devices can be flashed in the field without manual resets, and new firmware can still recover safely from corrupted storage.