The reactive data store for local-first apps.
"The One You Can Sync... with a server!"
It's Reactive
TinyBase lets you listen to changes 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 bindings to React and pre-built components let you easily build fully reactive UIs on top of TinyBase. You even get a built-in undo stack, and developer tools!
It's Database-Like
Consumer app? Enterprise app? Or even a game? Model key-value data and tabular data with optional typed schematization, whatever its data structures. There are built-in indexing, metric aggregation, and tabular relationships APIs - and a powerful query engine to select, join, filter, and group data (reactively!) without SQL.
It Synchronizes
TinyBase has native CRDT support, meaning that you can deterministically synchronize and merge data across multiple sources, clients, and servers. And although TinyBase is an in-memory data store, but you can easily persist your data to file, browser storage, IndexedDB, SQLite databases, and more.
It's Built For A Local-First World
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 5.3kB - 12.7kB and with no dependencies - yet 100% tested, fully documented, and of course, open source!
TinyBase works great on its own, but also plays well with friends!
Start with a simple key-value store.
Creating a Store
requires just a simple call to the createStore
function. Once you have one, you can easily set Values
in it by unique Id
. And of course you can easily get them back out again.
Read more about using keyed value data in The Basics guide.
import {createStore} from 'tinybase';
const store = createStore()
.setValues({employees: 3})
.setValue('open', true);
console.log(store.getValues());
// -> {employees: 3, open: true}
Level up to use tabular data.
For other types of data applications, a tabular data structure is more useful. TinyBase lets you set and get nested Table
, Row
, or Cell
data, by unique Id
- and in the same Store
as the keyed values!
Read more about setting and changing data in The Basics guide.
store
.setTable('pets', {fido: {species: 'dog'}})
.setCell('pets', 'fido', 'color', 'brown');
console.log(store.getRow('pets', 'fido'));
// -> {species: 'dog', color: 'brown'}
Register granular listeners.
The magic starts to happen when you register listeners on a Value
, Table
, Row
, or Cell
. They get called when any part of that object changes. You can also use wildcards - useful when you don't know the Id
of the objects that might change.
Read more about listeners in the Listening To Stores guide.
const listenerId = store.addTableListener('pets', () =>
console.log('changed'),
);
store.setCell('pets', 'fido', 'sold', false);
// -> 'changed'
store.delListener(listenerId);
Call hooks to bind to data.
If you're using React in your application, the optional ui-react
module provides hooks to bind to the data in a Store
.
More magic! The useCell
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.
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.
Read more about the using hooks in the Using React Hooks guide.
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'
Pre-built reactive components.
The ui-react
module provides bare React components that let you build up a fully reactive user interface based on a Store
.
For web applications in particular, the new ui-react-dom
module provides pre-built components for tabular display of your data, with lots of customization and interactivity options.
Try them out in the UI Components demos, and read more about the underlying ui-react
module in the Building UIs guides.
An inspector for your data.
If you are building a web application, the new Inspector
component lets you overlay a view of the data in your Store
, Indexes
, Relationships
, and so on. You can even edit the data in place and see it update in your app immediately.
Read more about this powerful new tool in the Inspecting Data guide.
Apply schemas to tables & values.
By default, a Store
can contain any arbitrary Value
, and a Row
can contain any arbitrary Cell
. But you can add a ValuesSchema
or a TablesSchema
to a