English for TinyBase Developers
Vocabulary for developers building local-first apps with TinyBase — stores, tables, indexes, and persisters — for teams discussing reactive in-app data in English.
TinyBase is a small, reactive, in-memory data store for building local-first JavaScript apps — structured like a lightweight relational database, but designed to sync, persist, and drive UI reactivity out of the box. Because it borrows vocabulary from both spreadsheets and relational databases, review conversations need precise terms to stay unambiguous. Here’s the English for talking about it clearly.
Stores and Tables
Store — TinyBase’s core object holding all data for an app, organized into tables, plus optional metadata (values) that aren’t tied to any specific row.
“Don’t create a second store for that feature — add another table to the existing store, so everything stays in one reactive graph.”
Table — a named collection of rows within a store, each row identified by a row ID, conceptually similar to a table in a relational database but schema-flexible.
“Each row in that table doesn’t need identical fields — TinyBase doesn’t enforce a rigid schema the way a SQL table would.”
Cell — a single value at the intersection of a row and a column within a table, the smallest unit of data TinyBase tracks changes on.
“You can listen for changes on just that one cell instead of the whole row — that’s the more precise, less wasteful way to wire this up.”
Reactivity
Listener — a callback registered on a store, table, row, or cell that fires automatically whenever the corresponding data changes.
“Attach the listener at the row level, not the whole table — right now every row’s UI re-renders whenever any row in the table changes.”
Reactive hook (React) — TinyBase’s React bindings (useCell, useRow, useTable) that subscribe a component to exactly the slice of data it renders, re-rendering only when that slice changes.
“Swap that manual listener plus
useStatefor theuseCellhook — it already handles subscribing and re-rendering for you.”
Query (via queries module) — a derived, reactively-updating view over a store’s data, similar to a SQL SELECT, that recomputes automatically as underlying data changes.
“Don’t recompute that filtered list manually on every render — define it as a query once, and let it update reactively.”
Persistence and Sync
Persister — the pluggable module responsible for saving a store’s data to and loading it from a specific target — localStorage, IndexedDB, SQLite, or a remote server.
“Swapping from the localStorage persister to the SQLite one didn’t require touching any component — that’s the whole point of the abstraction.”
Synchronizer — the module that keeps a local store in sync with a remote store or other local stores, handling the network layer on top of the persistence layer.
“The data’s saving fine locally — this is a synchronizer issue, not a persister issue, since it’s specifically not reaching the other device.”
Common Mistakes
- Saying “the store isn’t updating” without specifying whether it’s a listener that wasn’t attached, a persister that failed to save, or a synchronizer that failed to sync — three very different bugs.
- Subscribing to an entire table when only a single cell’s changes matter, causing unnecessary re-renders across the UI.
- Treating queries as one-time computations instead of reactive views, then manually re-running them after every data change instead of letting them update automatically.
Practice Exercise
- Explain, in two sentences, the difference between a store’s persister and its synchronizer to a teammate debugging a sync issue.
- Write a short PR description for narrowing a table-level listener down to a row-level listener to fix excessive re-renders.
- Draft a code review comment explaining why a filtered list should be defined as a query instead of recomputed manually on every render.