> ## Documentation Index
> Fetch the complete documentation index at: https://replyke-feat-push-rich-payload-fields.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Tables — Rows

> Read and write custom-table rows from your server with the client.table(name) accessor

Custom tables let you provision your own database tables alongside Sublay's built-in models. The `client.table(name)` accessor gives you full row-level access to a custom table from your server. For an overview of the feature — the `custom_` naming model, managed columns, and soft-delete — see [Custom Tables](/v7/custom-tables). To **create** tables and columns, see [Tables — Management](/v7/node-sdk/tables-management).

<Note>
  `client.table(name)` is a **callable accessor**, not a flat module namespace —
  it closes over the table name and returns the row-operation object. You can
  type the rows by passing a generic: `client.table<EventRow>("Events")`.
</Note>

```typescript theme={null}
interface EventRow {
  id: string;
  name: string;
  capacity: number;
  createdAt: string;
}

const events = sublay.table<EventRow>("Events");
const { data } = await events.find({ limit: 20 });
```

The `name` you pass is the **logical** table name — Sublay applies the `custom_` prefix for you.

***

### find

Fetches a filtered, sorted, paginated page of rows. Returns the shared `{ data, pagination }` envelope.

```typescript theme={null}
const { data, pagination } = await sublay.table<EventRow>("Events").find({
  page: 1,
  limit: 20,
  sortBy: "createdAt",
  sortDir: "desc",
  filters: [
    { column: "capacity", operator: "gte", value: 100 },
    { column: "name", operator: "contains", value: "summit" },
  ],
});
```

<ParamField body="page" type="number">
  Page number (1-indexed).
</ParamField>

<ParamField body="limit" type="number">
  Rows per page.
</ParamField>

<ParamField body="sortBy" type="string">
  Column to sort by. Validated against the table's real columns. Defaults to
  `createdAt` (descending) on a table with timestamps, otherwise `id`.
</ParamField>

<ParamField body="sortDir" type="&#x22;asc&#x22; | &#x22;desc&#x22;">
  Sort direction.
</ParamField>

<ParamField body="filters" type="DbFilter[]">
  An array of `{ column, operator, value }` clauses, **AND-combined**. Operators:
  `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `contains`, `like`, `isNull`.
  Serialized to a JSON query parameter for you.
</ParamField>

<ParamField body="includeDeleted" type="boolean">
  On a paranoid table, set `true` to include soft-deleted rows. Defaults to
  `false`.
</ParamField>

**Returns** — `Promise<PaginatedResponse<T>>`

***

### findOne

Fetches a single row by its `id`. Throws (axios `404`) if the row doesn't exist or has been soft-deleted.

```typescript theme={null}
const event = await sublay.table<EventRow>("Events").findOne("a1b2c3d4-...");
```

<ParamField body="rowId" type="string" required>
  The row's `id` (UUID).
</ParamField>

**Returns** — `Promise<T>`

***

### create

Inserts a single row. Managed columns (`id`, `createdAt`, `updatedAt`, `deletedAt`) are rejected from the body — they are set by the server.

```typescript theme={null}
const event = await sublay.table<EventRow>("Events").create({
  name: "Launch Summit",
  capacity: 250,
});
```

<ParamField body="data" type="Partial<T>" required>
  The column values for the new row.
</ParamField>

**Returns** — `Promise<T>`

***

### bulkCreate

Inserts many rows in one call. Capped at **100 rows** per request.

```typescript theme={null}
const rows = await sublay.table<EventRow>("Events").bulkCreate([
  { name: "Workshop A", capacity: 40 },
  { name: "Workshop B", capacity: 40 },
]);
```

<ParamField body="rows" type="Partial<T>[]" required>
  The rows to insert (max 100).
</ParamField>

**Returns** — `Promise<T[]>`

***

### update

Updates a row by `id`. On a table with timestamps, `updatedAt` is bumped automatically. Managed columns are rejected from the body.

```typescript theme={null}
const event = await sublay.table<EventRow>("Events").update("a1b2c3d4-...", {
  capacity: 300,
});
```

<ParamField body="rowId" type="string" required>
  The row's `id`.
</ParamField>

<ParamField body="data" type="Partial<T>" required>
  The column values to change.
</ParamField>

**Returns** — `Promise<T>`

***

### delete

Deletes a row by `id`. On a **paranoid** table this is a soft delete (sets `deletedAt`); pass `force: true` to hard-delete. On a non-paranoid table it is always a hard delete.

```typescript theme={null}
// Soft delete on a paranoid table
await sublay.table("Events").delete("a1b2c3d4-...");

// Hard delete
await sublay.table("Events").delete("a1b2c3d4-...", { force: true });
```

<ParamField body="rowId" type="string" required>
  The row's `id`.
</ParamField>

<ParamField body="opts.force" type="boolean">
  When `true`, hard-deletes a paranoid row instead of soft-deleting it.
</ParamField>

**Returns** — `Promise<{ deleted: boolean; soft: boolean }>` — `soft` is `true` when the row was soft-deleted.

***

### bulkDelete

Deletes many rows by an id list and/or a `filters` predicate (at least one is required). Paranoid-aware (soft by default, `force` to hard-delete) and capped at the bulk limit.

```typescript theme={null}
// By id list
await sublay.table("Events").bulkDelete({ rowIds: ["id-1", "id-2"] });

// By predicate
await sublay.table("Events").bulkDelete({
  filters: [{ column: "capacity", operator: "lt", value: 10 }],
  force: true,
});
```

<ParamField body="rowIds" type="string[]">
  Rows to delete by `id`.
</ParamField>

<ParamField body="filters" type="DbFilter[]">
  A predicate selecting rows to delete (same shape as `find`'s `filters`).
</ParamField>

<ParamField body="force" type="boolean">
  When `true`, hard-deletes matched paranoid rows.
</ParamField>

**Returns** — `Promise<{ deletedCount: number; soft: boolean }>`

***

### restore

Clears `deletedAt` on a soft-deleted row, bringing it back. Only valid on a **paranoid** table.

```typescript theme={null}
const event = await sublay.table<EventRow>("Events").restore("a1b2c3d4-...");
```

<ParamField body="rowId" type="string" required>
  The soft-deleted row's `id`.
</ParamField>

**Returns** — `Promise<T>`

***

<Warning>
  Row CRUD on the `/db` surface is currently **open** — identity is captured but
  not enforced. See the [security note](/v7/custom-tables#security-open-row-crud)
  on the overview page before storing access-controlled data in custom tables.
</Warning>
