Skip to main content

Run bulk operations

Bulk requests reduce round trips when several records need the same kind of operation. Use a bounded batch, keep a stable identifier on every record, and retain the original input so a failed request can be inspected or retried.

The examples use the tasks table from the quickstart. Generate firstTaskId and secondTaskId once in application code and reuse them through the sequence. The REST create example does the same with FIRST_TASK_ID and SECOND_TASK_ID in the current shell.

Create several records​

Send an array to the same data resource used to create one record.

await database
.from('tasks')
.create([
{id: firstTaskId, title: 'Prepare release notes', done: false},
{id: secondTaskId, title: 'Publish release notes', done: false},
])
.execute();

REST and the JavaScript builder return the created records in data. Python's direct create() method returns the created-record list.

Update several records​

Each bulk-update object must include the table's primary key and at least one field to change. The examples use the generated UUID field named id.

await database
.from('tasks')
.bulkUpdate([
{id: firstTaskId, done: true},
{id: secondTaskId, done: true},
])
.execute();

Bulk update responses place the updated records and their count in data.records and data.count.

Delete records by ID​

Prefer ID-based deletion when the application already knows the exact target set.

Review bulk targets
  • Affected resource and cascade: The target is the bounded list of record IDs in the named site, app, and table. Review foreign-key behavior for every selected record.
  • Reversibility: Bulk deletion is permanent.
  • Authorization: Treat authorization as a property of every record; the caller needs the table policy's delete action for the intended scope.
  • Backup or export: Export the selected records and retain the exact ID list when the workflow requires recovery.
  • Confirmation: Compare the site, app, table, ID list, and intended count with the records read immediately before the request.
  • Success response and postcondition: Compare deleted_count with the intended count, then read the IDs again and verify that they are absent.
  • Recovery: This guide documents no bulk undelete. Recreate records only from retained data and re-verify constraints and authorization.
await database
.from('tasks')
.bulkDelete([firstTaskId, secondTaskId])
.execute();

The response reports deleted_count.

Delete records selected by a filter​

Use the filter to select the records, review the complete target set, and save their id values as an application-owned manifest. Submit that manifest through the bulk-delete workflow above in bounded chunks.

If the manifest is too large to collect in one run, pause writes and repeatedly read page 1 after deleting each reviewed chunk. Do not advance to page 2 after deleting page 1: offset-based pages shift as records are removed and can skip targets. An immutable cutoff or a previously captured ID manifest provides the same protection when writes cannot be paused.

This select-review-delete workflow keeps every target visible and authorizes each selected record without exposing direct filter-wide deletion.

Plan a reliable batch​

  • Choose an explicit batch size of up to 1,000 records. Keep each batch small enough to review, read back, and retry independently.
  • Reuse application-owned UUIDs when reconciling a retry. A repeated create can return a duplicate-key conflict instead of inserting a second row.
  • Validate required fields and field types before sending the batch.
  • Treat authorization as a property of every record, not only the request.
  • Read data.count or deleted_count and compare it with the intended target count.
  • Split independent work into smaller batches when you need narrower retries or simpler diagnostics.

Next steps​