From React to Quilt

You know React. You know props, hooks, and the data flow. Quilt is the same idea scaled up — instead of components, you have cells. And instead of "lift state up", the state lives in the cell itself.

☕ Buy Casey a Coffee
The mental model: A Quilt cell is a "Smart Component" that acts like a mini-app. It owns its data fetching, state, and logic internally. You compose cells just like React components, but they manage their own lifecycle and dependencies. Think of it as a useEffect + useState bundle, encapsulated in a deployable silo.

The basic patterns

1. A value cell is like a useState

React

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>
        +
      </button>
    </div>
  );
}

Quilt

cells:
  count:
    kind: value
    value: 0
  message:
    kind: formula
    formula: '"Count is " + count'

In React, the value lives in component state. In Quilt, it lives in a cell. The cell is the source of truth, addressable by name, and any formula referencing it will update when it changes.

2. A formula cell is like a useMemo

React

function Display({ count }) {
  const doubled = useMemo(
    () => count * 2, [count]
  );
  return <div>{doubled}</div>;
}

Quilt

cells:
  count:
    kind: value
    value: 0
  doubled:
    kind: formula
    formula: "count * 2"

Same semantics — the formula re-evaluates when its dependencies change. But in Quilt, the formula is a cell, not a function call. You can address it from anywhere, subscribe to it, persist it.

3. An api cell is like a useEffect with fetch

React

function User({ id }) {
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetch(`/api/users/${id}`)
      .then(r => r.json())
      .then(setUser);
  }, [id]);
  if (!user) return <Loading/>;
  return <div>{user.name}</div>;
}

Quilt

cells:
  user:
    kind: api
    url: "https://api.example.com/users/{{id}}"
    cache_ttl: 60000
  user.name:
    kind: formula
    formula: "user.name"

The Quilt api cell has caching, error handling, and dependency tracking built in. The same URL with the same parameters is a content-addressed value — you can subscribe to it from anywhere in your app.

What Quilt adds that React doesn't

ConceptReactQuilt
State locationComponent treeA cell, addressable by name
Data flowProps down, callbacks upReactive propagation through the cell graph
Async datauseEffect + fetch + useStateOne api cell
Derived stateuseMemo + dependencies arrayA formula cell — deps are auto-discovered
Side effectsuseEffect with depsA listener cell — fires when upstream changes
LLM callsCustom hook with provider abstractionAn ai cell with built-in caching, content addressing
Cross-app sharingContext, Redux, ZustandSubscribe to any cell by URI, across tiers, across processes
PersistencelocalStorage, IndexedDB, server DBFederatedArtifactStore — 3-tier cache + R2 canonical
ReactivityBuilt into React, but statefulPure: cells have values, propagation is deterministic

The mental shift

In React, you think components. In Quilt, you think cells. The component model assumes a tree; the cell model assumes a graph. The component model assumes render; the cell model assumes propagation. The component model assumes local state; the cell model assumes addressable state.

When you start a Quilt project, you don't reach for a component. You reach for a cell:

// React: a component with state, props, effects
<UserProfile userId={42} onLogout={handleLogout} />

// Quilt: a graph of cells, all addressable
cells:
  user:
    kind: api
    url: "https://api.example.com/users/42"
  user.name:
    kind: formula
    formula: "user.name"
  is_logged_in:
    kind: formula
    formula: "user != null"
  on_logout:
    kind: listener
    depends_on: [is_logged_in]
    fn: "if (!is_logged_in) clearSession()"

You don't pass props. You address cells by name. The graph IS the app. The propagation IS the render. The subscription IS the re-render.

When to use which

Quilt isn't a React replacement. They have different sweet spots:

You can also use both: render Quilt cells as React props.

// In a React component
import { useCell } from '@quilt/react';

function Profile() {
  const user = useCell('user');
  return <div>{user.name}</div>;  // re-renders when the user cell changes
}

(@quilt/react is a thin adapter: useCell = cell => useState + useEffect subscribe.)

Try it

Open Quilt Live in your browser — a self-contained 70KB React-free Quilt runtime. Or run npm install @quilt/core and try the patterns above in your own app.

☕ Buy Casey a Coffee — support the work
Quilt is Apache 2.0. The cell model is the substrate.