<section id="hero"><h2 id="the-reactive-data-store-for-local-first-apps">The <em>reactive</em> data store for <span>local-first apps</span>.</h2></section><p><a href="https://tinybase.org/guides/releases/#v5-1"><em>NEW!</em> v5.1 release</a></p><p><span id="one-with">"The One You Can Sync... with a server!"</span></p><p><a class="start" href="https://tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://tinybase.org/demos/">Try the demos</a></p><p><a href="https://tinybase.org/api/store/interfaces/store/store/">Read the docs</a></p><hr><section><h2 id="it-s-reactive">It's <em>Reactive</em></h2><p>TinyBase lets you <a href="#register-granular-listeners">listen to changes</a> made to any part of your data. This means your app will be fast, since you only spend rendering cycles on things that change. The optional <a href="#call-hooks-to-bind-to-data">bindings to React</a> and <a href="#pre-built-reactive-components">pre-built components</a> let you easily build fully reactive UIs on top of TinyBase. You even get a built-in <a href="#set-checkpoints-for-an-undo-stack">undo stack</a>, and <a href="#an-inspector-for-your-data">developer tools</a>!</p></section><section><h2 id="it-s-database-like">It's <em>Database-Like</em></h2><p>Consumer app? Enterprise app? Or even a game? Model <a href="#start-with-a-simple-key-value-store">key-value data</a> and <a href="#level-up-to-use-tabular-data">tabular data</a> with optional typed <a href="#apply-schemas-to-tables-values">schematization</a>, whatever its data structures. There are built-in <a href="#create-indexes-for-fast-lookups">indexing</a>, <a href="#define-metrics-and-aggregations">metric aggregation</a>, and tabular <a href="#model-table-relationships">relationships</a> APIs - and a powerful <a href="#build-complex-queries-with-tinyql">query engine</a> to select, join, filter, and group data (reactively!) without SQL.</p></section><section><h2 id="it-synchronizes">It <em>Synchronizes</em></h2><p>TinyBase has <a href="#synchronize-between-devices">native CRDT</a> support, meaning that you can deterministically <a href="https://tinybase.org/guides/synchronization/">synchronize</a> and merge data across multiple sources, clients, and servers. And although TinyBase is an in-memory data store, but you can easily <a href="#persist-to-storage-sqlite-more">persist</a> your data to file, <a href="https://tinybase.org/api/persister-browser">browser storage</a>, <a href="https://tinybase.org/api/persister-indexed-db">IndexedDB</a>, <a href="https://tinybase.org/guides/persistence/database-persistence/">SQLite databases</a>, and <a href="https://tinybase.org/guides/persistence/third-party-crdt-persistence/">more</a>.</p></section><section><h2 id="it-s-built-for-a-local-first-world">It's Built For A <em>Local-First</em> World</h2><p>TinyBase works anywhere that JavaScript does, but it's especially great for local-first apps: where data is stored locally on the user's device and that can be run offline. It's tiny by name, tiny by nature: just <a href="#did-we-say-tiny">5.3kB - 12.7kB</a> and with no dependencies - yet <a href="#well-tested-and-documented">100% tested</a>, <a href="https://tinybase.org/guides/the-basics/getting-started/">fully documented</a>, and of course, <a href="https://github.com/tinyplex/tinybase">open source</a>!</p></section><hr><section id="friends"><h2 id="tinybase-works-great-on-its-own-but-also-plays-well-with-friends">TinyBase works great on its own, but also plays well with friends!</h2><div><a href="https://tinybase.org/guides/building-uis/getting-started-with-ui-react"><img width="48" src="https://tinybase.org/react.svg"> React</a></div><div><a href="https://tinybase.org/api/persister-partykit-client"><img width="48" src="https://tinybase.org/partykit.svg"> PartyKit</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img width="48" src="https://tinybase.org/expo.svg">Expo SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img width="48" src="https://tinybase.org/electric.svg">ElectricSQL</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img width="48" src="https://tinybase.org/sqlite.svg"> SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img width="48" src="https://tinybase.org/turso.svg">Turso</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img width="48" src="https://tinybase.org/powersync.svg">PowerSync</a></div><div><a href="https://tinybase.org/api/persister-indexed-db/functions/creation/createindexeddbpersister"><img width="48" src="https://tinybase.org/indexeddb.svg"> IndexedDB</a></div><div><a href="https://tinybase.org/api/persister-yjs/functions/creation/createyjspersister"><img width="48" src="https://tinybase.org/yjs.svg"> YJS</a></div><div><a href="https://tinybase.org/api/persister-cr-sqlite-wasm"><img width="48" src="https://tinybase.org/crsqlite.png"> CR-SQLite</a></div><div><a href="https://tinybase.org/api/persister-automerge"><img width="48" src="https://tinybase.org/automerge.svg"> Automerge</a></div></section><hr><section id="follow"><a href="https://github.com/tinyplex/tinybase" target="_blank"><img src="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=GitHub&labelColor=%23d81b60&color=%23333"> </a><a href="https://discord.com/invite/mGz3mevwP8" target="_blank"><img src="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&logo=discord&logoColor=%23fff&label=Discord&labelColor=%233131e8&color=%23333"> </a><a href="https://twitter.com/tinybasejs" target="_blank"><img src="https://img.shields.io/twitter/follow/tinybasejs?style=for-the-badge&logo=x&logoColor=%23fff&label=Twitter&labelColor=%23333&color=%23333"></a><br><a href="https://github.com/tinyplex/tinybase/discussions" target="_blank"><img src="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=Ideas&labelColor=%23d81b60&color=%23333"> </a><a href="https://github.com/tinyplex/tinybase/issues" target="_blank"><img src="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=Issues&labelColor=%23d81b60&color=%23333"> </a><a href="#well-tested-and-documented"><img src="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&logo=jest&logoColor=%23fff&color=%23333&labelColor=%2387c305"> </a><a href="https://www.npmjs.com/package/tinybase/v/5.1.4" target="_blank"><img src="https://img.shields.io/npm/v/tinybase?style=for-the-badge&logo=npm&logoColor=%23fff&labelColor=%23bd0005&color=%23333"></a></section><hr><section><h2 id="start-with-a-simple-key-value-store">Start with a simple key-value store.</h2><p>Creating a <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a> requires just a simple call to the <a href="https://tinybase.org/api/store/functions/creation/createstore/"><code>createStore</code></a> function. Once you have one, you can easily set <a href="https://tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> in it by unique <a href="https://tinybase.org/api/common/type-aliases/identity/id/"><code>Id</code></a>. And of course you can easily get them back out again.</p><p>Read more about using keyed value data in <a href="https://tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
import {createStore} from 'tinybase';
const store = createStore()
.setValues({employees: 3})
.setValue('open', true);
console.log(store.getValues());
// -> {employees: 3, open: true}
<section><h2 id="level-up-to-use-tabular-data">Level up to use tabular data.</h2><p>For other types of data applications, a tabular data structure is more useful. TinyBase lets you set and get nested <a href="https://tinybase.org/api/store/type-aliases/store/table/"><code>Table</code></a>, <a href="https://tinybase.org/api/store/type-aliases/store/row/"><code>Row</code></a>, or <a href="https://tinybase.org/api/store/type-aliases/store/cell/"><code>Cell</code></a> data, by unique <a href="https://tinybase.org/api/common/type-aliases/identity/id/"><code>Id</code></a> - and in the same <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a> as the keyed values!</p><p>Read more about setting and changing data in <a href="https://tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
store
.setTable('pets', {fido: {species: 'dog'}})
.setCell('pets', 'fido', 'color', 'brown');
console.log(store.getRow('pets', 'fido'));
// -> {species: 'dog', color: 'brown'}
<section><h2 id="register-granular-listeners">Register granular listeners.</h2><p>The magic starts to happen when you register listeners on a <a href="https://tinybase.org/api/store/type-aliases/store/value/"><code>Value</code></a>, <a href="https://tinybase.org/api/store/type-aliases/store/table/"><code>Table</code></a>, <a href="https://tinybase.org/api/store/type-aliases/store/row/"><code>Row</code></a>, or <a href="https://tinybase.org/api/store/type-aliases/store/cell/"><code>Cell</code></a>. They get called when any part of that object changes. You can also use wildcards - useful when you don't know the <a href="https://tinybase.org/api/common/type-aliases/identity/id/"><code>Id</code></a> of the objects that might change.</p><p>Read more about listeners in the <a href="https://tinybase.org/guides/the-basics/listening-to-stores/">Listening To Stores</a> guide.</p></section>
const listenerId = store.addTableListener('pets', () =>
console.log('changed'),
);
store.setCell('pets', 'fido', 'sold', false);
// -> 'changed'
store.delListener(listenerId);
<section><h2 id="call-hooks-to-bind-to-data">Call hooks to bind to data.</h2><p>If you're using React in your application, the optional <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module provides hooks to bind to the data in a <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a>.</p><p>More magic! The <a href="https://tinybase.org/api/ui-react/functions/store-hooks/usecell/"><code>useCell</code></a> hook in this example fetches the dog's color. But it also registers a listener on that cell that will fire and re-render the component whenever the value changes.</p><p>Basically you simply describe what data you want in your user interface and TinyBase will take care of the whole lifecycle of updating it for you.</p><p>Read more about the using hooks in the <a href="https://tinybase.org/guides/building-uis/using-react-hooks/">Using React Hooks</a> guide.</p></section>
import React from 'react';
import {createRoot} from 'react-dom/client';
import {useCell} from 'tinybase/ui-react';
const App1 = () => {
const color = useCell('pets', 'fido', 'color', store);
return <>Color: {color}</>;
};
const app = document.createElement('div');
const root = createRoot(app);
root.render(<App1 />);
console.log(app.innerHTML);
// -> 'Color: brown'
store.setCell('pets', 'fido', 'color', 'walnut');
console.log(app.innerHTML);
// -> 'Color: walnut'
<section><h2 id="pre-built-reactive-components">Pre-built reactive components.</h2><p>The <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module provides bare React components that let you build up a fully reactive user interface based on a <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a>.</p><p>For web applications in particular, the new <a href="https://tinybase.org/api/ui-react-dom/"><code>ui-react-dom</code></a> module provides pre-built components for tabular display of your data, with lots of customization and interactivity options.</p><p>Try them out in the <a href="https://tinybase.org/demos/ui-components/">UI Components</a> demos, and read more about the underlying <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module in the <a href="https://tinybase.org/guides/building-uis/">Building UIs</a> guides.</p></section><img src="https://tinybase.org/ui-react-dom.webp"><section><h2 id="an-inspector-for-your-data">An inspector for your data.</h2><p>If you are building a web application, the new <a href="https://tinybase.org/api/ui-react-inspector/functions/development-components/inspector/"><code>Inspector</code></a> component lets you overlay a view of the data in your <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a>, <a href="https://tinybase.org/api/indexes/interfaces/indexes/indexes/"><code>Indexes</code></a>, <a href="https://tinybase.org/api/relationships/interfaces/relationships/relationships/"><code>Relationships</code></a>, and so on. You can even edit the data in place and see it update in your app immediately.</p><p>Read more about this powerful new tool in the <a href="https://tinybase.org/guides/developer-tools/inspecting-data/">Inspecting Data</a> guide.</p></section><img src="https://tinybase.org/store-inspector.webp"><section><h2 id="apply-schemas-to-tables-values">Apply schemas to tables & values.</h2><p>By default, a <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a> can contain any arbitrary <a href="https://tinybase.org/api/store/type-aliases/store/value/"><code>Value</code></a>, and a <a href="https://tinybase.org/api/store/type-aliases/store/row/"><code>Row</code></a> can contain any arbitrary <a href="https://tinybase.org/api/store/type-aliases/store/cell/"><code>Cell</code></a>. But you can add a <a href="https://tinybase.org/api/store/type-aliases/schema/valuesschema/"><code>ValuesSchema</code></a> or a <a href="https://tinybase.org/api/store/type-aliases/schema/tablesschema/"><code>TablesSchema</code></a> to a <a