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.
| Approach | Connector calls for 1000 updates | Typical behavior |
|---|---|---|
| Apply to each with Update item | 1000 | Simple but slow |
| Apply to each with concurrency | 1000 | Faster but can throttle |
| REST batch with 10 groups | 10 | Faster and more controlled |
| REST batch plus per-item parsing | 10 | Best 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 code | Meaning | Handling |
|---|---|---|
| 201 | Item created | Mark source as created |
| 204 | Item updated | Mark source as updated |
| 400 | Bad payload or field value | Log item failure |
| 404 | List or item not found | Stop batch and investigate |
| 429 | Throttled | Retry batch with backoff |
| 500 | Server failure | Retry 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.
| Workload | Apply to each | Batch API | Practical gain |
|---|---|---|---|
| 100 creates | 2 to 5 minutes | 10 to 25 seconds | Strong |
| 1000 updates | 20 to 45 minutes | 2 to 6 minutes | Very strong |
| 5000 mixed writes | Often unreliable | Chunked job | Operationally 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
15 Power Automate Expressions Every Maker Should Memorize
Memorize these Power Automate expressions to build faster flows, handle nulls, shape arrays, format dates, reduce action count, and debug WDL.
Calling the Dataverse Web API from Power Automate with the HTTP Action
Learn when to call the Dataverse Web API from Power Automate for actions, functions, batch requests, impersonation, row association, and binds.
Child Flows in Power Automate: Reuse, Pass Data, and Avoid Duplication
Use child flows in Power Automate to centralize reusable logic, pass typed inputs and outputs, handle errors, reduce duplication, and improve ALM.
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.