6 min readRishi

Batch Create and Update SharePoint Items in Power Automate with the $batch API

The standard Apply to each pattern is fine for twenty SharePoint items. It becomes painful when a nightly flow needs to create or update thousands of rows and every item costs another connector round trip. SharePoint's batch endpoint lets Power Automate send many writes in one HTTP request, if you build the multipart body correctly.

The batch endpoint reduces connector chatter

The SharePoint REST batch endpoint accepts multiple operations in one call. In Power Automate, use Send an HTTP request to SharePoint and post to _api/$batch. The request body is multipart MIME. For create and update operations, the writes sit inside a changeset.

The payoff is round-trip reduction. Instead of one HTTP action per item inside Apply to each, you build a batch body for a group of items, send it once, parse the response, and continue with the next group.

ApproachConnector calls for 1000 updatesTypical behavior
Apply to each with Update item1000Simple but slow
Apply to each with concurrency1000Faster but can throttle
REST batch with 10 groups10Faster and more controlled
REST batch plus per-item parsing10Best operational visibility

Batching is not magic parallelism. It is a more efficient HTTP contract. You still need limits, retry handling, and a way to identify which item failed.

Changesets are the unit for writes

A batch can contain one or more changesets. For SharePoint writes, keep the design simple: one changeset per batch request, and a practical maximum around one hundred operations per changeset. SharePoint and service limits change over time, but a conservative design avoids payload size and timeout problems. Across a full job, process up to roughly one thousand operations at a time before checkpointing.

The body has two boundaries: one for the batch and one for the changeset. Each operation has its own content ID, method, URL, headers, and JSON payload.

--batch_123
Content-Type: multipart/mixed; boundary=changeset_456

--changeset_456
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

POST https://contoso.sharepoint.com/sites/ops/_api/web/lists/getbytitle('Orders')/items HTTP/1.1
Content-Type: application/json;odata=verbose

{ "__metadata": { "type": "SP.Data.OrdersListItem" }, "Title": "Order-1001", "Status": "New" }
--changeset_456
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

PATCH https://contoso.sharepoint.com/sites/ops/_api/web/lists/getbytitle('Orders')/items(42) HTTP/1.1
Content-Type: application/json;odata=verbose
IF-MATCH: *
X-HTTP-Method: MERGE

{ "__metadata": { "type": "SP.Data.OrdersListItem" }, "Status": "Processed" }
--changeset_456--
--batch_123--

The blank lines are part of the protocol. Multipart bodies are unforgiving. A missing boundary, missing blank line, or incorrect content type can turn a good design into a cryptic bad request.

Build the body from an array, not string chaos

Power Automate can assemble the batch body in a controlled loop. Start with an array of normalized operations. Each operation should include an operation ID, method, relative endpoint, entity type, payload, and source record key. Then chunk the array into groups.

Use variables for the boundaries so the header and body agree:

{
  "batchBoundary": "batch_20260430_001",
  "changeSetBoundary": "changeset_20260430_001",
  "operationsPerBatch": 100,
  "listEntityType": "SP.Data.OrdersListItem"
}

Prefer predictable content IDs. Set Content-ID to the operation index or source row number. When the response comes back, you can map failures to business records instead of guessing from position.

For updates, use IF-MATCH: * only when overwriting the latest item is acceptable. If concurrency matters, retrieve and pass the expected ETag. Batching should not weaken your data rules.

The HTTP action needs exact headers

Send the request to the site that owns the list. The action URI should be _api/$batch. The method is POST. The Content-Type header must include the batch boundary. The Accept header should match the OData flavor you are using.

Method: POST
Uri: _api/$batch
Headers:
  Accept: application/json;odata=verbose
  Content-Type: multipart/mixed; boundary=batch_20260430_001
Body:
  multipart batch body

Keep authentication inside the connector. The SharePoint HTTP action handles the connection. Do not manually store tokens in the flow. If you need application permissions or cross-site operations, evaluate a custom connector or Azure-hosted worker instead of forcing secrets into actions.

Response parsing is where production quality shows

A batch response can contain mixed success and failure. Do not treat the outer HTTP status as the only result. Parse each operation section, read the status code, and map it back to Content-ID. A batch can return success for the request while one item failed validation.

Response codeMeaningHandling
201Item createdMark source as created
204Item updatedMark source as updated
400Bad payload or field valueLog item failure
404List or item not foundStop batch and investigate
429ThrottledRetry batch with backoff
500Server failureRetry if safe

Log per item, not only per batch. Store the source key, Content-ID, HTTP code, and response message. If one payload has an invalid choice value, operations should fix that row rather than rerun the whole job blind.

Batching changes the performance conversation

The speed-up can be dramatic because latency dominates small writes. In many tenant environments, simple item updates inside Apply to each take hundreds of milliseconds each before business logic is considered. Batching compresses the overhead.

WorkloadApply to eachBatch APIPractical gain
100 creates2 to 5 minutes10 to 25 secondsStrong
1000 updates20 to 45 minutes2 to 6 minutesVery strong
5000 mixed writesOften unreliableChunked jobOperationally manageable

Measure in your tenant. List complexity, column types, flows running at the same time, and throttling all change the numbers. The point is not a universal benchmark. The point is that fewer connector round trips usually wins.

Use SharePoint batching when the process is truly bulk-oriented and you can own the error handling. For small lists and simple flows, the standard connector is easier. For nightly syncs, migrations, and high-volume status updates, _api/$batch is the difference between hoping the loop finishes and engineering a job that actually does.

Keep reading

Newsletter

New posts, straight to your inbox

One email per post. No spam, no tracking pixels, unsubscribe anytime.

Comments

No comments yet. Be the first.