Docs site recipe | Spacefast

The dish

What it makes.

docs.view.fast

v2.3 v2.4 · local-first state for TypeScript

Reactive data for web apps, in 4 kilobytes.

Local-first state for the web. Define typed collections, write reactive queries, and persist to IndexedDB — in 4 kB, with zero dependencies.

$npm i ledgerCopy

Why Ledger

A data layer that gets out of your way

Everything you need to model, query, and persist app state — without dragging in a database server or a megabyte of client code.

Type-safe by default

Collections are generic. Inserts, queries, and results are fully inferred — no codegen, no decorators.

Reactive queries

Call .live() on any query and subscribe. Ledger recomputes only what changed and emits the new result.

Local-first

Pluggable IndexedDB and localStorage adapters keep data on the device and survive reloads and offline use.

4 kB, zero deps

The whole core is 4 kB min+gzip with no runtime dependencies. Tree-shakeable down to what you import.

Framework bindings

First-party hooks for React, Vue, and Svelte. The core is framework-agnostic and works in plain JS too.

Safe migrations

Version your schema and ship migration steps. Ledger upgrades stored data on load, in order, exactly once.

Quick look

Define a collection, write a live query

Ledger queries are plain functions over typed records. Add .live() and you get a subscription that stays in sync as data changes — no manual invalidation.

import { createLedger, collection } from 'ledger';

type Todo = { id: string; text: string; done: boolean };

const db = createLedger({
  todos: collection<Todo>(),
});

// A live query re-runs whenever matching data changes.
const active = db.todos.where((t) => !t.done).sort('text').live();
active.subscribe((todos) => render(todos));

db.todos.insert({ id: 't1', text: 'Ship the docs', done: false });
// → subscriber fires with [{ id: 't1', text: 'Ship the docs', done: false }]

TodoList.tsx

import { useQuery } from 'ledger/react';

function TodoList() {
  const todos = useQuery(() => db.todos.where((t) => !t.done).live());
  return <ul>{todos.map((t) => <li key={t.id}>{t.text}</li>)}</ul>;
}

Framework bindings

One hook, zero boilerplate

The React binding turns any live query into reactive component state. The same query works untouched on the server, in a worker, or in plain JavaScript.

4 kB min + gzip

0 dependencies

100% typed API

MIT licensed

Start here

Pick a path

Whether you're wiring up your first store or migrating a production schema, there's a short guide for it.

Your ingredients

Your agent will ask.

Answer these once. The recipe uses your details instead of placeholder copy.

  1. What's the library/product and a one-line description of what it does?
  2. What are the top 4–5 doc sections (e.g. Getting started, Guides, API reference, Changelog)?
  3. Give me one real code example to feature on the landing page.
  4. (Optional) What's the brand accent color, and the GitHub / npm links?

The method

The whole prompt.

Paste this into Claude, ChatGPT, Codex, Cursor, or another coding agent. It builds the site and publishes it to Spacefast.