← Back to archive

Repo of the Day

tinyplex/tinybase

Published: Feb 1, 2023

Open repository ↗

The reactive data store for local‑first apps.

Summary

TinyBase is a reactive in-memory data store for JavaScript and TypeScript, distributed under the MIT license, that adds persistence and synchronization on top of a small core. It targets local-first apps that need to work offline, respond quickly, and reconcile state once they reconnect. The library has no dependencies and is reported to weigh between 7.3kB and 16.4kB.

What it is useful for

TinyBase is useful when you want a single store that holds both key-value data and tabular data, then reactively updates listeners, React/Solid/Svelte hooks, and pre-built components as values change. Built-in indexing, metrics, relationships, and a reactive query engine (TinyQL) let you select, join, filter, and group data without writing SQL. A native CRDT layer handles synchronization across clients and servers, which suits collaborative or multi-device features. Schema validation is available through Zod, TypeBox, Valibot, ArkType, Yup, or Effect, and the library also includes an undo stack and a developer inspector.

For storage, TinyBase ships with persisters for IndexedDB, OPFS, SQLite (Bun, Expo, Capacitor, Turso, PowerSync), PostgreSQL, PGlite, SQL Server (added in v10.0), Neon, and Supabase, plus sync adapters for Cloudflare Durable Objects, PartyKit, YJS, and Automerge.

How engineers can use it

The README documents a single scaffold command for a new project: npm create tinybase@latest.

To use TinyBase in an existing codebase, import createStore and combine keyed values with a table:

import {createStore} from 'tinybase';

const store = createStore()
  .setValues({employees: 3})
  .setTable('pets', {fido: {species: 'dog'}})
  .setCell('pets', 'fido', 'color', 'brown');

Register listeners to react to changes:

store.addTableListener('pets', () => console.log('changed'));

For UI work, install the matching binding package (for example, tinybase/ui-react) and use hooks like useCell to bind a component to a specific cell. Persistence and sync are added by importing the appropriate persister or sync module and wiring it to the store; the README points to the persistence and synchronization guides for the exact steps for each backend.

Documented constraints: each persistence, UI, schema, and sync integration is a separate module, so installation and configuration differ by target. The README does not contain the per-backend wiring details, so consult the linked guides before integrating a specific storage or sync provider.