Skip to content

Implemented a catalogue‑driven deep‑merge

Implemented a catalogue‑driven deep‑merge for stored JSON preferences, preventing missing‑key crashes as the schema evolves.

  • Puzzle pieces, puzzle, share
    Photo: congerdesign / Pixabay
  • Zipper, wallet, cramp
    Photo: Myriams-Fotos / Pixabay

stored preferences that survive a schema change

Situation. The platform stores JSON preferences — notification settings and the like — as a user’s saved values laid over a set of defaults. The original merge did that at a single level. The problem shows up later: add a new key to the defaults, and rows saved before that key existed simply don’t have it. Then some client code reads that field, gets undefined, and falls over — for exactly the users who’ve been around longest.

Task. Evolving the preference schema had to be safe, so that adding a setting could never break the people who signed up before it existed.

Action. The single‑level merge was replaced with a deep‑merge driven by the defaults as a catalogue. The defaults are treated as the authoritative list of every key that should exist; the user’s stored values are merged recursively on top, so anything in the catalogue is guaranteed to come out present, whether or not it was in the saved blob. Add a key to the defaults and it appears in every existing row’s effective preferences automatically, nested keys included. It rolled in through a migration so existing data got the benefit straight away rather than waiting to be rewritten.

Result. Preferences can grow without fear. Adding a setting no longer risks an undefined‑field crash in the client, and the frontend stopped needing defensive checks scattered around every place it reads a preference. It also gave the rest of the platform a dependable way to extend any stored‑JSON blob — the pattern, not just the one fix.

One piece of a longer record — and it is all on this site.

Every entry is written the same way: the situation, the task, what we did and what changed.

See the whole record