> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chardb.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Live queries

> Register a typed Drizzle query and keep its React result current.

A live query is a registered Drizzle query. The browser sends its reference and validated JSON arguments. It never sends SQL.

## Register the query

This is the complete generated query file.

```ts src/queries.ts theme={null}
import { api } from "@chardb/core/server";
import { desc, eq } from "drizzle-orm";
import { z } from "zod";
import { messages } from "./schema.ts";

export const listMessages = api.query({
  ref: "messages#list",
  args: z.object({
    organizationId: z.string(),
    limit: z.number().int().min(1).max(100).default(50),
  }),
  query: (db, args) => db
    .select()
    .from(messages)
    .where(eq(messages.organizationId, args.organizationId))
    .orderBy(desc(messages.createdAt), desc(messages.id))
    .limit(args.limit),
});
```

Keep `ref` stable after release. It identifies the query across the browser bundle, Worker, reconnects, and pending subscriptions.

The organization predicate is required even though CharDB also applies the ownership policy. It tells the router which partition can answer the query.

## Subscribe in React

Configure one client with the public Worker URL and the same Better Auth client. CharDB derives `/ws` from this URL.

```tsx src/web/App.tsx theme={null}
const workerUrl = window.location.origin;
const db = createChardbReactClient({
  url: workerUrl,
  ownership: "organization",
  auth: ({ baseURL }) => createAuthClient({
    baseURL,
    plugins: [anonymousClient(), organizationClient(), jwtClient()],
  }),
});
```

Pass the exported handle to the configured client. It reads the active organization from Better Auth and adds `organizationId` to the wire arguments.

```tsx src/MessageList.tsx theme={null}
import { listMessages } from "./queries.ts";

export function MessageList() {
  const { data: messages = [], state } = db.useQuery(listMessages, {
    limit: 50,
  });

  if (state === "pending") return <p>Loading messages...</p>;

  return messages.map((message) => (
    <p key={message.id}>{message.body}</p>
  ));
}
```

`pending` means the first snapshot has not arrived. `live` means the subscription is current. `refetching` means CharDB could not safely resume an earlier snapshot and is replacing it.

## Write through a mutation

```tsx theme={null}
const post = db.useMutation(postMessage);

await post({
  id: crypto.randomUUID(),
  body: "ship it",
});
```

The client adds the active organization and retains one mutation ID while it reconnects, so a retry does not create a second write. Every matching subscription receives a complete replacement snapshot after the commit.

Use [Files](/files) when a row needs an attachment.
