# Work with data

> Create, read, update, delete and subscribe to records with ds.entities.


```ts
// Create
const task = await ds.entities.Task.create({ title: "Ship it" });
await ds.entities.Task.bulkCreate([{ title: "A" }, { title: "B" }]);

// Read
const all = await ds.entities.Task.list();                 // newest first
const sorted = await ds.entities.Task.list("-priority", 20);
const open = await ds.entities.Task.filter({ done: false }, "-created_date", 50);
const one = await ds.entities.Task.get(task.id);
const n = await ds.entities.Task.count({ done: true });

// Update
await ds.entities.Task.update(task.id, { done: true });
await ds.entities.Task.updateMany({ done: false }, { priority: "high" });
await ds.entities.Task.bulkUpdate([{ id: a.id, done: true }, { id: b.id, done: false }]);

// Delete
await ds.entities.Task.delete(task.id);
await ds.entities.Task.deleteMany({ done: true });

// Live list: called now and again the moment anyone changes a matching record.
// Returns an unsubscribe function (call it when the component unmounts).
const stop = ds.entities.Task.subscribe((tasks) => setTasks(tasks), { done: false });

// Single change events: { type: "create" | "update" | "delete", id, data, timestamp }
const off = ds.entities.Task.onChange((e) => console.log(`${e.id} was ${e.type}d`, e.data));
```

Signatures: `list(sort?, limit?, skip?)` and `filter(query, sort?, limit?, skip?)`. Query syntax is described in [Entities overview](/docs/developers/backend/entities). Results only include records the current user may read; writes the user isn't allowed to make throw a 403 `DraftshipError`.

## A typical component

```tsx
"use client";
import { useEffect, useState } from "react";
import { ds, type DsRecord } from "@/lib/draftship";

export function Tasks() {
  const [tasks, setTasks] = useState<DsRecord[] | null>(null);
  const [error, setError] = useState<string | null>(null);
  useEffect(() => {
    ds.entities.Task.list().then(setTasks).catch((e) => setError(e.message));
  }, []);
  if (error) return <p>{error}</p>;
  if (!tasks) return <p>Loading…</p>;
  return <ul>{tasks.map((t) => <li key={t.id}>{String(t.title)}</li>)}</ul>;
}
```

## Realtime

Live updates arrive over one shared connection per page (server-sent events from `/_ds/realtime`). Each person only receives changes to records they're allowed to read, with hidden fields removed, exactly like a normal read. The connection reconnects automatically and switches permissions when someone signs in or out.

Outside the SDK you can listen directly:

```bash
curl -N "https://<your-app>/_ds/realtime?entities=Task,Note" -H "Authorization: Bearer <token>"
```

## Deleting and restoring

`delete` and `deleteMany` move records to the trash, where they stay for 30 days. Owners can restore them from **Dashboard → Backups & trash**.
