SkillAtlasSkill 详情

build-with-tinybase

Local first.

审核状态:已审核Quality 80Security 80

复制安装命令

用 Codex 或 Claude 安装复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它先审查 Skill 页面再帮你安装。

复制前请先查看来源、License 和安全提示。

项目 README

来源文件:readme.md

抓取于 2026年8月3日

Local first.

Sync on demand.

Fast always.

TinyBase is a reactive in-memory data store with persistence and synchronization for local-first JavaScript and TypeScript apps that need to feel instant, work offline, and stay consistent when they come back online.

NEW! v9.3 release

"The one with fewer sockets!"

Get started

Try the demos

Read the docs


Your first TinyBase app

Create a todo list, a chat app, a drawing tool, a charting app, or a tic-tac-toe game - with sync & persistence! - in less than 60s.

> npm create tinybase@latest

📦 Creating your project...

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, pre-built components, and charts 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, you can easily persist your data to file, browser storage, IndexedDB, SQLite or PostgreSQL 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 7.2kB - 15.6kB 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.

UI Frameworks

Storage & Sync

Schema Systems

(Baffled by all these logos? Check out our architectural options guide to make sense of it all!)




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);

Bind to data in UI libraries.

If you're using React, Solid, or Svelte in your application, the optional ui-react module, ui-solid module, or ui-svelte module provide hooks and functions to bind to the data in a Store.

For example, 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 and the Building UIs With Svelte 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'

root.unmount();

Pre-built reactive components.

The UI modules also provide bare React, Solid, and Svelte components that let you build up a fully reactive user interface based on a Store.

It's super easy to wire up tabular display of your data with lots of customization and interactivity options.

Try them out in the UI Components (React), Chart Components (React), UI Components (Solid), and UI Components (Svelte) demos, and read more in the Building UIs guides.

Local-first data visualizations.

Render TinyBase data and queries directly as responsive, styleable SVG charts with the ui-react-dom-charts module. These charts update reactively when data changes, and are composable with labels, bounds, ticks, and time-aware x-axes.

Try the Chart Components (React) demos, or read more in the Using Charts guide.

An inspector for your data.

If you are building a web application with React or Svelte, the 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.

Want clean data? You can add a ValuesSchema or a TablesSchema to a Store to ensure that they are always what you expect by constraining types, and providing defaults. There are even TypeScript definitions that infer API types from the data schemas you apply.

And our 'schematizer' modules let you convert schemas from libraries like Zod, TypeBox, Valibot, ArkType, Yup, and Effect Schema into TinyBase at runtime.

Read more about schemas in the Schemas guide.

store.setTablesSchema({
  pets: {
    species: {type: 'string'},
    color: {type: 'string'},
    sold: {type: 'boolean', default: false},
  },
});

store.setRow('pets', 'polly', {species: 'parrot'});
console.log(store.getRow('pets', 'polly'));
// -> {species: 'parrot', sold: false}

store.delTablesSchema();

Synchronize between devices.

The MergeableStore type acts as a native CRDT, letting you merge data and synchronize it between clients and systems - or even a server. The synchronization protocol can run over WebSockets, the browser BroadcastChannel, or your own custom synchronization medium.

Read more about these techniques in the Synchronization guides.

import {WebSocketServer, WebSocket} from 'ws';
import {createMergeableStore} from 'tinybase';
import {createWsServer} from 'tinybase/synchronizers/synchronizer-ws-server';
import {createWsSynchronizer} from 'tinybase/synchronizers/synchronizer-ws-client';

// On a server machine:
const server = createWsServer(
  new WebSocketServer({port: 8040}),
);

// On a client machine:
const store1 = createMergeableStore();
const synchronizer1 = await createWsSynchronizer(
  store1,
  new WebSocket('ws://localhost:8040'),
);
await synchronizer1.startSync();

// ...

await synchronizer1.destroy();
await server.destroy();

Persist to storage or a database.

You can easily persist a Store between browser page reloads or sessions. You can also synchronize it with a web endpoint, or (if you're using TinyBase in an appropriate environment), load and save it to a file. You can bind TinyBase to various flavors of database, or to Yjs and Automerge CRDT documents.

Read more about persisters in the Persistence guides.

import {createSessionPersister} from 'tinybase/persisters/persister-browser';

const persister = createSessionPersister(store, 'demo');
await persister.save();

console.log(sessionStorage.getItem('demo'));
// ->
`
[
  {
    "pets":{
      "fido":{"species":"dog","color":"walnut","sold":false},
      "polly":{"species":"parrot","sold":false}
    }
  },
  {"employees":3,"open":true}
]
`;

await persister.destroy();
await sessionStorage.clear();

Build complex queries with TinyQL.

The Queries object lets you query data across tables, with filtering and aggregation - using a SQL-adjacent syntax called TinyQL.

Accessors and listeners let you sort and paginate the results efficiently, making building rich tabular interfaces easier than ever.

In this example, we have two tables: of pets and their owners. They are joined together by the pet's ownerId Cell. We select the pet's species, and the owner's state, and then aggregate the prices for the combinations.

We access the results by descending price, essentially answering the question: "which is the highest-priced species, and in which state?"

Needless to say, the results are reactive too! You can add listeners to queries, and since v7.2, even parameterize them.

Read more about Queries in the v2.0 Release Notes, the Using Queries guide, and the Car Analysis demo and Movie Database demo.

import {createQueries} from 'tinybase';

store
  .setTable('pets', {
    fido: {species: 'dog', ownerId: '1', price: 5},
    rex: {species: 'dog', ownerId: '2', price: 4},
    felix: {species: 'cat', ownerId: '2', price: 3},
    cujo: {species: 'dog', ownerId: '3', price: 4},
  })
  .setTable('owners', {
    1: {name: 'Alice', state: 'CA'},
    2: {name: 'Bob', state: 'CA'},
    3: {name: 'Carol', state: 'WA'},
  });

const queries = createQueries(store);
queries.setQueryDefinition(
  'prices',
  'pets',
  ({select, join, group}) => {
    select('species');
    select('owners', 'state');
    select('price');
    join('owners', 'ownerId');
    group('price', 'avg').as('avgPrice');
  },
);

queries
  .getResultSortedRowIds('prices', 'avgPrice', true)
  .forEach((rowId) => {
    console.log(queries.getResultRow('prices', rowId));
  });
// -> {species: 'dog', state: 'CA', avgPrice: 4.5}
// -> {species: 'dog', state: 'WA', avgPrice: 4}
// -> {species: 'cat', state: 'CA', avgPrice: 3}

queries.destroy();

Define metrics and aggregations.

A Metrics object makes it easy to keep a running aggregation of Cell values in each Row of a Table. This is useful for counting rows, but also supports averages, ranges of values, or arbitrary aggregations.

In this example, we create a new table of the pet species, and keep a track of which is most expensive. When we add horses to our pet store, the listener detects that the highest price has changed.

Read more about Metrics in the Using Metrics guide.

import {createMetrics} from 'tinybase';

store.setTable('species', {
  dog: {price: 5},
  cat: {price: 4},
  worm: {price: 1},
});

const metrics = createMetrics(store);
metrics.setMetricDefinition(
  'highestPrice', // metricId
  'species', //      tableId to aggregate
  'max', //          aggregation
  'price', //        cellId to aggregate
);

console.log(metrics.getMetric('highestPrice'));
// -> 5

metrics.addMetricListener('highestPrice', () =>
  console.log(metrics.getMetric('highestPrice')),
);
store.setCell('species', 'horse', 'price', 20);
// -> 20

metrics.destroy();

Create indexes for fast lookups.

An Indexes object makes it easy to look up all the Row objects that have a certain value in a Cell.

In this example, we create an index on the species Cell values. We can then get the the list of distinct Cell value present for that index (known as 'slices'), and the set of Row objects that match each value.

Indexes objects are reactive too. So you can set listeners on them just as you do for the data in the underlying Store.

Read more about Indexes in the Using Indexes guide.

import {createIndexes} from 'tinybase';

const indexes = createIndexes(store);
indexes.setIndexDefinition(
  'bySpecies', // indexId
  'pets', //      tableId to index
  'species', //   cellId to index
);

console.log(indexes.getSliceIds('bySpecies'));
// -> ['dog', 'cat']
console.log(indexes.getSliceRowIds('bySpecies', 'dog'));
// -> ['fido', 'rex', 'cujo']

indexes.addSliceIdsListener('bySpecies', () =>
  console.log(indexes.getSliceIds('bySpecies')),
);
store.setRow('pets', 'lowly', {species: 'worm'});
// -> ['dog', 'cat', 'worm']

indexes.destroy();

Model table relationships.

A Relationships object lets you associate a Row in a local Table with the Id of a Row in a remote Table. You can also reference a table to itself to create linked lists.

In this example, the species Cell of the pets Table is used to create a relationship to the species Table, so that we can access the price of a given pet.

Like everything else, you can set listeners on Relationships too.

Read more about Relationships in the Using Relationships guide.

import {createRelationships} from 'tinybase';

const relationships = createRelationships(store);
relationships.setRelationshipDefinition(
  'petSpecies', // relationshipId
  'pets', //       local tableId to link from
  'species', //    remote tableId to link to
  'species', //    cellId containing remote key
);

console.log(
  store.getCell(
    relationships.getRemoteTableId('petSpecies'),
    relationships.getRemoteRowId('petSpecies', 'fido'),
    'price',
  ),
);
// -> 5

relationships.destroy();

Set checkpoints for an undo stack.

A Checkpoints object lets you set checkpoints on a Store. Move forward and backward through them to create undo and redo functions.

In this example, we set a checkpoint, then sell one of the pets. Later, the pet is brought back to the shop, and we go back to that checkpoint to revert the store to its previous state.

Read more about Checkpoints in the Using Checkpoints guide.

import {createCheckpoints} from 'tinybase';

const checkpoints = createCheckpoints(store);

store.setCell('pets', 'felix', 'sold', false);
checkpoints.addCheckpoint('pre-sale');

store.setCell('pets', 'felix', 'sold', true);
console.log(store.getCell('pets', 'felix', 'sold'));
// -> true

checkpoints.goBackward();
console.log(store.getCell('pets', 'felix', 'sold'));
// -> false

Did we say tiny?

If you use the basic store module alone, you'll only add a gzipped 7.2kB to your app. Incrementally add the other modules as you need more functionality, or get it all for 15.6kB.

The optional ui-react module is just 5.9kB, the ui-react-dom components are another 4.3kB, and everything is super fast. Life is easy when you have zero dependencies!

Read more about how TinyBase is structured and packaged in the Architecture guide.

 Minified .js.gzSource .js
tinybase/store (minimal)7.2kB77.7kB
tinybase (complete)15.6kB175.2kB
ui-react5.9kB64.2kB
ui-react-dom4.3kB38.4kB
ui-react-dom-charts8.7kB64.9kB
ui-solid5.8kB63.2kB
ui-solid-dom4.9kB48.0kB
ui-svelte5.1kB62.5kB
ui-svelte-dom6.0kB62.0kB

Well tested and documented.

TinyBase has 100.0% test coverage, including the code throughout the documentation - even on this page! The guides, demos, and API examples are designed to make it as easy as possible for you to get your TinyBase-powered app up and running.

Read more about how TinyBase is tested in the Unit Testing guide.

 TotalTestedCoverage
Tested lines4,9844,984100.0%
Tested statements5,4035,403100.0%
Tested functions2,3852,385100.0%
Tested branches1,6841,684100.0%
Tests8,942
Assertions37,451

Proud to be supported by:

Excited to be used by:


Get started

Try the demos

Read the docs


Meet the family

TinyBase is part of a group of small libraries designed to help make rich client and local-first apps easier to build. Check out the others!


Synclets

An open, storage-agnostic, sync engine development kit.


TinyWidgets

A collection of tiny, reusable, UI components.


TinyTick

A tiny but very useful task orchestrator.


About

Modern apps deserve better. Why trade reactive user experiences to be able to use relational data? Or sacrifice features for bundle size? And why does the cloud do all the work anyway?

Building TinyBase was originally an interesting exercise for me in [API](/api/) design, minification, and documentation. But now it has taken on a life of its own, and has grown beyond my wildest expectations.

It could not have been built without these great projects and friends, and I hope you enjoy using it as much as I do building it!

The story

浏览器与自动化

中风险

  • 来源需自行核对维护者身份。
  • 包含脚本或命令调用,安装前请复核。
  • 未检测到明显外部权限要求。
  • 未检测到高风险命令。
  • 扫描发现:2 条。

Codex — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/tinyplex/tinybase.git
  3. 将 "skills/build-with-tinybase" 文件夹复制到 Codex 的 skills 目录中。
  4. 重启 Codex 让新的 skill 生效。

Codex — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Codex 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Codex 让新的 skill 生效。

Claude Code — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/tinyplex/tinybase.git
  3. 将 "skills/build-with-tinybase" 文件夹复制到 Claude Code 的 skills 目录中。
  4. 重启 Claude Code 让新的 skill 生效。

Claude Code — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Claude Code 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Claude Code 让新的 skill 生效。

Cursor — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/tinyplex/tinybase.git
  3. 将 "skills/build-with-tinybase" 文件夹复制到 Cursor 的 skills 目录中。
  4. 重启 Cursor 让新的 skill 生效。

Cursor — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Cursor 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Cursor 让新的 skill 生效。

GitHub Copilot — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/tinyplex/tinybase.git
  3. 将 "skills/build-with-tinybase" 文件夹复制到 GitHub Copilot 的 skills 目录中。
  4. 重启 GitHub Copilot 让新的 skill 生效。

GitHub Copilot — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 GitHub Copilot 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 GitHub Copilot 让新的 skill 生效。

Windsurf — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/tinyplex/tinybase.git
  3. 将 "skills/build-with-tinybase" 文件夹复制到 Windsurf 的 skills 目录中。
  4. 重启 Windsurf 让新的 skill 生效。

Windsurf — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Windsurf 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Windsurf 让新的 skill 生效。
查看 SKILL.md 原文
name: build-with-tinybase
description: Scaffold, extend, and verify reactive local-first JavaScript or TypeScript applications with TinyBase. Use when choosing TinyBase for in-memory tabular or key-value state, generating an app with create-tinybase, adding schemas or UI bindings, configuring browser or database persistence, configuring MergeableStore synchronization, or diagnosing an existing TinyBase application.

Build With TinyBase

Prefer a current generated application over reconstructing TinyBase setup from memory. Preserve persistence and synchronization lifecycle ordering, and verify the behavior the user actually needs.

Select The Architecture

Read references/architecture.md when choosing between Store and MergeableStore, persistence backends, synchronization, or UI bindings.

Confirm that TinyBase fits the task:

  • Keep the active application dataset in a JavaScript runtime.
  • Use TinyBase for reactive tabular or key-value data, local-first behavior, persistence, synchronization, or framework bindings.
  • Do not present TinyBase as a hosted database service.
  • Pair it with another database or service when the authoritative dataset is unbounded, primarily queried on a server, or requires managed backend facilities.

Scaffold A New Application

Inspect the installed generator contract first:

npm create tinybase@latest -- --list-options

Translate the user's requirements into explicit values. Generate unattended projects with every applicable option and always disable automatic installation and server startup:

npm create tinybase@latest -- \
  --non-interactive \
  --projectName my-tinybase-app \
  --appType todos \
  --language typescript \
  --framework react \
  --tinyWidgets false \
  --schemas true \
  --syncType none \
  --persistenceType local-storage \
  --prettier true \
  --eslint true \
  --installAndRun false

Run the generator in the parent directory that should contain the new project. Do not overwrite an existing directory. After generation:

  1. Read the generated AGENTS.md and README.md.
  2. Inspect the primary Store file before modifying application code.
  3. Install dependencies only when authorized and required.
  4. Make application-specific changes within the generated architecture.
  5. Run the generated client build.
  6. Run the server build when server code changed.

Extend An Existing Application

Inspect package.json, TinyBase imports, Store creation, Persister setup, and Synchronizer setup before editing. Use documentation matching the installed TinyBase version. Start at https://tinybase.org/llms.txt or retrieve current TinyBase documentation through Context7 when available.

Keep these boundaries clear:

  • Store creation and schemas
  • persistence startup and teardown
  • synchronization startup and teardown
  • framework Provider or context wiring
  • application-specific data and UI

Reuse existing imports and patterns when they are current. Import integrations from their specific tinybase/... subpaths. Avoid adding a second source of truth in component state for data already owned by TinyBase.

Verify The Outcome

Match verification to the requested behavior:

  • Run the project's build or type check after code changes.
  • For persistence, change data and perform a real reload or restart.
  • For synchronization, connect two clients to the same channel or room and confirm changes propagate in both directions.
  • Test reconnection when synchronization behavior changes.
  • Confirm schema rejection and inferred types when changing schemas.
  • Report any verification that could not be performed.

Do not treat compilation alone as proof of persistence or synchronization.

发现问题?提交给管理员复核

评分:

评论 (0)

暂无评论,成为第一个评论者吧!