Skip to content
Build
Markdown

Store data

Document collections with a small API, scoped automatically to the work that uses them.

Start with a collection

Call db.collection(name) inside a work. A collection appears when its first record is written; there is no separate provisioning step. Feature and collection names start with a lowercase letter and contain lowercase letters, digits, underscores, or hyphens, up to 48 characters.

Create a record inside a handler
const notes = db.collection("notes");
const saved = await notes.create({ message: "Ready to go", status: "new" });
const sameNote = await notes.get(saved.id);

Each document is { id, data, revision, createdAt, updatedAt }. A missing get(id) returns null. You can provide a stable ID with create(data, { id }); an existing ID produces a write conflict.

Understand the data scope

Records are scoped by store + feature + environment. Two works with the same feature in the same store and environment share collections. A different feature or environment has separate data. Your code cannot select another store’s namespace.

Read and filter

List one page
const page = await db.collection("notes").list({
  where: { status: "new" },
  limit: 25,
});

// Continue only when nextCursor is non-null.
if (page.nextCursor) {
  const nextPage = await db.collection("notes").list({
    where: { status: "new" },
    limit: 25,
    after: page.nextCursor,
  });
}

Lists return { items, nextCursor }. The maximum page size is 100 documents. Filters support up to five top-level scalar equality comparisons. Pagination orders by document ID, not creation time. There are no joins, full-text search, arbitrary sorting, or SQL access.

Update and delete with a revision

Replace a document
const notes = db.collection("notes");
const current = await notes.get(input.id);
if (!current) return Response.json({ error: "Not found" }, { status: 404 });

return notes.update(current.id, {
  ...current.data,
  status: "reviewed",
}, { revision: current.revision });

An update replaces the entire data object. Keep existing fields explicitly if you want to preserve them. Updates and deletes require the revision you read. A stale revision produces WRITE_CONFLICT; reload and reassess before retrying.

Delete a document
await notes.delete(current.id, { revision: current.revision });

Write an atomic batch

Two changes, one transaction
await db.batch([
  { type: "create", collection: "notes", id: "note-001", data: { message: "Hello" } },
  { type: "create", collection: "receipts", id: "receipt-001", data: { noteId: "note-001" } },
]);

A batch supports up to 10 operations on distinct documents within the current scope. Every operation succeeds or the entire batch fails. A database batch does not include Shopify requests; it cannot roll back a Shopify mutation.