CRUD API
Collection CRUD operations — find, findOne, create, update, delete, count, versions, and workflow transitions.
Collections expose typed CRUD operations on the server runtime and through questpie/client. Server code receives collection APIs from handler context; client code calls the generated client.
find(options)
const result = await collections.posts.find({
where: { status: "published" },
orderBy: { createdAt: "desc" },
limit: 20,
offset: 0,
with: { author: true },
stage: "published",
});Returns: { docs: T[], totalDocs: number }
findOne(options)
const record = await collections.posts.findOne({
where: { id: "post_123" },
with: { author: true },
stage: "published",
});Returns: T | null
When versioning workflow is enabled, stage reads the latest version snapshot for that stage. Omit it to read the working stage.
create(data)
const record = await collections.posts.create(
{
title: "Hello",
body: "World",
},
{ stage: "draft" },
);Returns: T (created record)
updateById(options)
const record = await collections.posts.updateById(
{
id: "post_123",
data: { title: "Updated title" },
},
{ stage: "draft" },
);Returns: T (updated record)
On the client SDK, the same operation is exposed as update({ id, data }):
const updated = await client.collections.posts.update(
{
id: "post_123",
data: { title: "Updated title" },
},
{ stage: "draft" },
);deleteById(options)
await collections.posts.deleteById({ id: "post_123" });count(options)
const count = await collections.posts.count({
where: { status: "published" },
});Returns: number
update(options)
await collections.posts.update({
where: { status: "draft" },
data: { title: "Needs review" },
});Server update() updates every record matching where. On the client SDK this operation is named updateMany().
delete(options)
await collections.posts.delete({
where: { status: "archived" },
});Server delete() deletes every record matching where. On the client SDK this operation is named deleteMany().
findVersions(options)
const versions = await collections.posts.findVersions({
id: "post_123",
limit: 20,
});Returns: version rows with versionId, versionNumber, versionOperation, versionUserId, and versionCreatedAt.
revertToVersion(options)
const restored = await collections.posts.revertToVersion({
id: "post_123",
version: 4,
});Pass versionId instead of version when you already have the version row ID.
transitionStage(options)
const published = await collections.posts.transitionStage({
id: "post_123",
stage: "published",
});To schedule a future transition:
await collections.posts.transitionStage({
id: "post_123",
stage: "published",
scheduledAt: new Date("2026-05-01T09:00:00Z"),
});transitionStage() requires versioning.workflow, validates the target stage and transition graph, checks access.transition with fallback to access.update, runs transition hooks, and creates a version snapshot without mutating the working row.
Client API
The client SDK mirrors the same resource behavior with browser-friendly method names:
const posts = await client.collections.posts.find({ stage: "published" });
const post = await client.collections.posts.findOne({
where: { id: "post_123" },
});
const created = await client.collections.posts.create({ title: "Hello" });
const updated = await client.collections.posts.update({
id: "post_123",
data: { title: "Updated title" },
});
await client.collections.posts.delete({ id: "post_123" });
const count = await client.collections.posts.count({
where: { status: "published" },
});
await client.collections.posts.transitionStage({
id: "post_123",
stage: "published",
scheduledAt: "2026-05-01T09:00:00.000Z",
});Upload Methods
For upload collections:
const asset = await client.collections.assets.upload(file, {
onProgress: (percent) => {
console.log(percent);
},
});
const assets = await client.collections.assets.uploadMany(files, {
onProgress: (percent, fileIndex) => {
console.log(percent, fileIndex);
},
});