Writes return the saved record, so you can show the server’s version (with its id, timestamps and defaults) without another read. Every write is checked against the table’s create, update or delete rule and against the columns’ rules.

Create

Leave out id, created_at and updated_at. If the table has an owner field, it is filled with the caller’s id.

Update some fields

update changes only the fields you send. Sending null clears an optional field. A required field (one that isn’t marked nullable) can’t be set to null: that’s a ValidationError.

Fields your rule depends on can’t be changed

If your table’s update rule reads a field, for example “only the owner may update” reads owner_id, then that field can’t be changed by your app’s users: the update is refused with PermissionError, naming the field. This stops someone handing a record to another person, or moving it into a team they’re not in. Change those fields from your server with a secret key, or from a flow.

Replace

replace sends the record with PUT. The server treats it exactly like update: it changes the fields you send and leaves the others as they are. It does not clear fields you leave out.
To clear a field, send it as null (if it’s optional). Prefer update; replace exists for code that thinks in whole records.

Delete

Deleting a record that’s gone throws NotFoundError. If the delete rule refuses, a signed-in person gets PermissionError and an anonymous caller gets NotFoundError. There’s no recycle bin: for “undo”, use a soft delete.

Validation errors

The server checks required columns, types and constraints before your rules run, and tells you which column is wrong:
Show fieldError("email") under each input. Define the rules once, in Columns and types, and they apply to every client. A taken unique value (a duplicate username) is a ConflictError:

What each write needs

Optimistic updates

Update the screen first, confirm with the server, roll back on failure:

Avoid duplicate creates

A double-click or a retry can create two records. Two defences:
  1. A unique column on a natural key (order_number, or an idempotency key you generate on the client), so the second attempt is a ConflictError you can treat as success.
  2. Disable the button while the request is in flight.
The client doesn’t retry a POST after a network drop by itself, to avoid exactly this.

Concurrent edits

Two people editing the same record: the last write wins. To detect it, send the updated_at you read and check it on the server (a route), or make fields independent so edits don’t collide.

Realtime echo

If the table broadcasts changes, you receive your own write back as a message. Merge by id so you don’t add it twice (Live records).

Bulk writes

Many at once.

Access

Why a write is refused.