Skip to main content
The Batch API allows you to execute multiple API requests atomically within a single database transaction. This is useful for maintaining data consistency across related operations and reducing network round trips.
All requests in a batch are executed sequentially within a single database transaction. If any request fails, all changes are rolled back.

Execute batch requests

Submit multiple requests to be executed atomically in a single transaction.
POST /api/batch
Authentication: Optional (inherited by all batch requests)

Request body

requests
array
required
Array of internal request objects to execute. Each request object contains:
requests[].method
string
required
HTTP method: POST, PATCH, PUT, or DELETE
requests[].url
string
required
API endpoint URL (relative path starting with /api/)
requests[].body
object
Request body data (for POST, PATCH, PUT requests)
requests[].headers
object
Custom headers for this specific request (Authorization headers are ignored - auth is inherited from the parent request)

Response

Returns an array of results for each request in the batch.
body
any
Response body from the individual request
status
number
HTTP status code from the individual request
curl -X POST http://127.0.0.1:8090/api/batch \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requests": [
      {
        "method": "POST",
        "url": "/api/collections/posts/records",
        "body": {
          "title": "First Post",
          "content": "Hello world"
        }
      },
      {
        "method": "POST",
        "url": "/api/collections/posts/records",
        "body": {
          "title": "Second Post",
          "content": "Another post"
        }
      }
    ]
  }'

Supported operations

The Batch API supports the following record operations:

Create record

{
  "method": "POST",
  "url": "/api/collections/{collection}/records",
  "body": { /* record data */ }
}

Update record

{
  "method": "PATCH",
  "url": "/api/collections/{collection}/records/{id}",
  "body": { /* updated fields */ }
}

Upsert record

{
  "method": "PUT",
  "url": "/api/collections/{collection}/records",
  "body": {
    "id": "RECORD_ID",
    /* record data */
  }
}
PUT (upsert) operations automatically determine whether to create or update based on whether the record ID exists. If the ID exists, it updates; otherwise, it creates a new record.

Delete record

{
  "method": "DELETE",
  "url": "/api/collections/{collection}/records/{id}"
}

Use cases

Atomic operations

Ensure multiple related records are created or updated together, or none at all:
curl -X POST http://127.0.0.1:8090/api/batch \
  -H "Content-Type: application/json" \
  -d '{
    "requests": [
      {
        "method": "POST",
        "url": "/api/collections/users/records",
        "body": {
          "username": "john_doe",
          "email": "john@example.com",
          "password": "secure_password",
          "passwordConfirm": "secure_password"
        }
      },
      {
        "method": "POST",
        "url": "/api/collections/profiles/records",
        "body": {
          "user": "@request.data.requests.0.body.id",
          "bio": "Software developer",
          "avatar": ""
        }
      }
    ]
  }'

Reducing round trips

Submit multiple independent operations in a single request:
curl -X POST http://127.0.0.1:8090/api/batch \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requests": [
      {
        "method": "DELETE",
        "url": "/api/collections/tasks/records/TASK_1"
      },
      {
        "method": "DELETE",
        "url": "/api/collections/tasks/records/TASK_2"
      },
      {
        "method": "DELETE",
        "url": "/api/collections/tasks/records/TASK_3"
      }
    ]
  }'

File uploads

When uploading files in batch requests, use multipart/form-data:
curl -X POST http://127.0.0.1:8090/api/batch \
  -H "Authorization: Bearer TOKEN" \
  -F '@jsonPayload={
    "requests": [
      {
        "method": "POST",
        "url": "/api/collections/posts/records",
        "body": {
          "title": "Post with image"
        }
      }
    ]
  }' \
  -F 'requests.0.image=@/path/to/image.jpg'
When using multipart/form-data:
  • Put regular fields in @jsonPayload as serialized JSON
  • Name file fields as requests.N.fieldName or requests[N].fieldName where N is the request index

Error handling

If any request in the batch fails, the entire transaction is rolled back and no changes are persisted.
{
  "code": 400,
  "message": "Failed to create record.",
  "data": {
    "requests": {
      "1": {
        "code": "batch_request_failed",
        "message": "Batch request failed.",
        "response": {
          "code": 400,
          "message": "Failed to create record.",
          "data": {
            "title": {
              "code": "validation_required",
              "message": "Missing required value."
            }
          }
        }
      }
    }
  }
}
The error response indicates:
  • Which request in the batch failed (index in the requests object)
  • The specific error from that request in the response field

Configuration

The Batch API must be enabled in your PocketBase settings. Configure these options:
batch.enabled
boolean
default:false
Enable or disable batch requests globally
batch.maxRequests
number
default:10
Maximum number of requests allowed per batch
batch.maxBodySize
number
default:134217728
Maximum total body size in bytes (default: 128 MB)
batch.timeout
number
default:3
Transaction timeout in seconds
If batch requests are disabled or the timeout is reached, the request will fail and return a 403 Forbidden or timeout error.

Limitations and best practices

Limitations

  1. Supported operations only - Only record create, update, upsert, and delete operations are supported
  2. No nested batches - Cannot include batch requests within a batch
  3. Sequential execution - Requests execute sequentially, not in parallel
  4. Shared authentication - All requests inherit auth from the parent batch request
  5. Timeout constraints - Long-running batches may timeout (default: 3 seconds)

Best practices

  1. Keep batches small - Use batches for related operations, not bulk data imports
  2. Handle errors gracefully - Prepare for all-or-nothing transaction behavior
  3. Monitor timeout - Ensure batch operations complete within the configured timeout
  4. Use for consistency - Ideal for maintaining referential integrity across collections
  5. Consider alternatives - For large bulk operations, use individual requests or direct database access

Performance considerations

  • Batch requests execute within a database transaction, which locks tables
  • Each request in the batch is validated and executed sequentially
  • File uploads in batches count toward the total body size limit
  • Transaction timeout prevents long-running operations from blocking the database

Common errors

CodeDescription
400Invalid batch request data or one of the requests failed
403Batch requests are disabled or not allowed
408Batch transaction timeout exceeded
413Request body exceeds maximum size limit

Example: Multi-step workflow

Create a complete blog post with tags and metadata atomically:
curl -X POST http://127.0.0.1:8090/api/batch \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requests": [
      {
        "method": "POST",
        "url": "/api/collections/posts/records",
        "body": {
          "title": "Getting Started with PocketBase",
          "slug": "getting-started-pocketbase",
          "content": "PocketBase is an open-source backend...",
          "published": true
        }
      },
      {
        "method": "POST",
        "url": "/api/collections/tags/records",
        "body": {
          "name": "tutorial",
          "post": "@request.data.requests.0.body.id"
        }
      },
      {
        "method": "POST",
        "url": "/api/collections/tags/records",
        "body": {
          "name": "pocketbase",
          "post": "@request.data.requests.0.body.id"
        }
      },
      {
        "method": "POST",
        "url": "/api/collections/post_stats/records",
        "body": {
          "post": "@request.data.requests.0.body.id",
          "views": 0,
          "likes": 0
        }
      }
    ]
  }'
Use @request.data.requests.N.body.id to reference the ID of a record created in a previous request within the same batch.