Blocks

Block Persistence Model

Vextro uses an inline-first persistence model for blocks. Understanding this model helps when building custom renderers, debugging save/load issues, or designing complex nested layouts.

Inline vs reference blocks

Every block in the editor tree is either inline or a reference:

KindWhere data livesWhen used
InlineEmbedded in the parent (document field or parent block's children array)Default for new blocks. Data, children, and layout are all in-place.
ReferenceOn a separate block row in the databaseWhen a block is "saved as shared." The document stores a thin pointer; data lives on the block row.

New blocks start inline. Authors can explicitly promote a block to shared (reference), at which point a block row is created and the inline entry becomes a thin pointer.

Mixed trees

A single block tree can mix both kinds at any level:

Document field
├── Inline hero block (data embedded here)
│   └── Reference CTA (pointer → block row j97x)
└── Reference Layout (pointer → block row k82m)
    ├── Inline text block (data on block row k82m's children)
    └── Reference CTA (pointer → block row ghi7)

The rule is simple: follow the kind. If inline, everything is in the parent. If reference, the entry is a thin pointer — follow the blockId to the block row.

Save ordering

On document save, within a single Convex mutation:

  1. Serialize the EditorBlock[] tree to BlockEntry[] (inline data + reference pointers)
  2. Walk the tree depth-first (leaves first)
  3. For each reference block: create or update its block row
  4. Replace any temporary IDs with real Convex document IDs
  5. Write the document field
  6. Sync block usage tracking

All writes happen in one Convex mutation — if any step fails, everything rolls back.

Grid zone persistence

Layout blocks in grid mode use gridZones — a map from cell keys (e.g., r0c0) to arrays of block IDs placed in that cell. This is stored on the Layout block (inline or block row) alongside the children array. See the Layout block docs for details.

Vextro preserves a valid gridZones map across unrelated edits, copies, and save/reload cycles. Invalid or incomplete placement data is normalized at the editor boundary so every child remains reachable without rewriting valid placements.

Previous
Renderer API