Records
Runtime instances of objects: how to fetch, create, update, and delete them with React hooks.
Records are the runtime instances of objects. The React hooks in @stndrds/react load and mutate them.
// @noverify
import { useCreateRecord, useRecords } from "@stndrds/react";
function ContactList() {
const { data: contacts, isLoading } = useRecords("contacts");
const create = useCreateRecord("contacts");
if (isLoading) return null;
return (
<ul>
{contacts?.data.map((c) => (
<li key={c.id}>{c.values.firstName}</li>
))}
</ul>
);
}useRecords takes the object name as a positional string argument, not a config object. The response is { data: ObjectRecord[], total: number }.
Breaking in vNEXT: the TypedRecord and BaseRecord aliases are gone — ObjectRecord<TValues> is now the single record type (generic on its values). Replace TypedRecord / BaseRecord imports with ObjectRecord. Date fields on a returned record (createdAt, updatedAt, deletedAt) are now hydrated to Date objects rather than ISO strings.
Hook surface
| Hook | Use case |
|---|---|
useRecord | fetch one record by id |
useRecords | fetch a list |
useSearchRecords | text search |
useInfiniteSearchRecords | paginated search |
useCreateRecord | create |
useUpdateRecord | update |
useDeleteRecord | delete single (soft — moves to archive) |
useRestoreRecord | restore a soft-deleted record |
usePurgeRecord | permanently destroy a soft-deleted record |
useBulkDeleteRecords | bulk delete |
useObject / useObjects | fetch object definitions |
useMyProfile | current actor |
useSchemaClient | direct client access (escape hatch) |
Query keys
Always use the recordsKeys factory from @stndrds/react when interacting with the query cache. Never write ad-hoc key arrays — the factory guarantees that invalidations cover all cache shapes (list, detail, grid, kanban).
// @noverify
import { recordsKeys } from "@stndrds/react";
import { useQueryClient } from "@tanstack/react-query";
const queryClient = useQueryClient();
queryClient.invalidateQueries({
queryKey: recordsKeys.list("contacts"),
});Available keys: all, lists, list, details, detail, grids, grid, kanbans, kanban, search, searchInfinite.
Optimistic updates
Optimistic update logic lives in @stndrds/react hooks (useUpdateRecord.onMutate). The pattern snapshots all relevant caches, applies the update immediately, and rolls back on error. Do not replicate this logic in @stndrds/ui components.
Optimistic updates belong in @stndrds/react, never in @stndrds/ui. The useRecordSave hook in @stndrds/ui is a thin wrapper — it does not touch the query cache.
Create and update now reject unknown attribute keys with HTTP 400 (ValidationError listing every offending key). Previously, unknown keys were silently persisted. If you pass validate: false, unknown keys are stripped instead of rejected — but the storage layer drops them either way. Make sure your payloads only carry attributes declared on the object.
Deletion is now a soft-delete: useDeleteRecord archives the record (sets deletedAt) and cascade-archives its edges. Restore via useRestoreRecord — only cascade-tagged edges wake up; edges independently archived stay archived. To permanently destroy a record, soft-delete it first, then call usePurgeRecord (requires manage permission).