Custom Serialization Adapters: 94% Payload Compression

7 min readYaseen Khatib · MERN + AI Architect

Rich UI objects make terrible database records. In IntegrateX — a node-graph automation tool — the thing the user drags around the canvas carries measured geometry, interaction flags, handle definitions, and framework internals. Persist that verbatim and every save writes kilobytes of cache. A custom Serialization Adapter pattern stripped it to the domain essentials and cut payloads by 94%.

Two models, one boundary

The naive design conflates two things that should never be the same: the render model (what the UI library needs to draw) and the transport model (what the database and wire actually require). An adapter translates between them in both directions, and nothing crosses the boundary without passing through it.

adapter.ts
// render model → lean transport record (and back)
export const toRecord = (node: FlowNode): NodeRecord => ({
  id: node.id,
  type: node.type,
  x: Math.round(node.position.x),
  y: Math.round(node.position.y),
  config: node.data.config,   // the only domain data that matters
});

export const fromRecord = (r: NodeRecord): FlowNode =>
  hydrate(r, defaults(r.type));   // recompute view state, don't store it

Derived, never stored

The principle that powers the compression: anything that can be derived must never be stored. Measured dimensions are derived from layout. Selection is ephemeral. Handle geometry is a function of the node type. Persisting them is persisting a cache — and caches do not belong in your source of truth.

The 94%, decomposed

The reduction is not a clever codec; it is the sum of removing what was never needed. Drop the measured geometry, the per-node flags, the duplicated handles, and the framework metadata, round coordinates to integers, and a node that serialized to roughly a kilobyte collapses to a few dozen bytes. Across a hundred-node graph, that is the entire performance profile of save, load, and real-time sync.

Most payload-size problems are not compression problems — they are boundary problems. You are shipping the cache because nobody drew the line between the view and the record.

For the state-management side of the same project, see Compressing the Wire; the system is IntegrateX.

Looking to architect a similar system?

Let's ship it at AI-speed.

Start a conversation →