Problem: We load large derived datasets into a component's tables and need readers to switch from the old data to the new data atomically, only after we have verified the new data, with the ability to switch back. npx convex import --replace already does most of this internally. Each table is written to a new hidden tablet, validated, and then finalize_import swaps the table mapping for all imported tables at once. But none of those steps is exposed separately. We can't import into a hidden state, read or verify the hidden data before it goes live, choose when to activate, or keep the previous tables for a quick rollback. Today our only options are to publish unverified data instantly, or to build our own versioned tables and a pointer on top of Convex.
Proposal: Expose the existing import pipeline as a staged, component-scoped operation:
- Stage: import a snapshot ZIP into hidden tables for a named component. Return a staging handle, per-table row counts, and a content digest. Nothing is visible to normal queries.
- Inspect: an authorized, read-only API (or admin-scoped queries) that can read the staged tables, so we can run our own verification before activation.
- Activate: conditionally and atomically swap all staged tables into place in one step. It succeeds only if the staging handle and the expected current table versions still match, like compare-and-swap.
- Retain and roll back: keep the previous table mapping for a declared lease period. Allow a reverse activation to restore it, and release it explicitly when no longer needed.
- Document the effects on file storage references,
creationTime/idpreservation, and the Data Sync (streaming export) cursor, for example whether consumers must rebaseline after activation.
Why it matters: This turns Convex's existing internal table swap into a safe, zero-downtime publish-and-rollback primitive. It's the pattern teams already use elsewhere: build the new version beside the old, verify it, flip one pointer. Anyone doing bulk recomputation, data migrations, or AI-derived datasets could publish verified data without downtime and roll back in seconds, instead of rebuilding versioned tables by hand or restoring a backup.
Current workaround. Keep two or more versions of each table (or a generationId column), route every query through an active-version pointer, and manage retention and cleanup ourselves. It works, but it touches every read path and duplicates what the importer already does.