> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom batch

> Perform several indexing operations in one API call.

export const Legacy = ({title, href}) => {
  return <Note>

    This page documents an earlier version of the API client.
    For the latest version, see <a href={href}>{title}</a>.

    </Note>;
};

<Legacy title="Batch indexing operations on one index" href="/doc/libraries/sdk/methods/search/batch" />

**Required ACL:** `depends on operations performed inside the batch`

This method lets you **batch multiple indexing operations** in one API request,
such as adding or deleting records, potentially targeting multiple indices.

Benefits:

* Reduced latency. Only one network trip is required for multiple operations.
* Data integrity. All operations inside the batch are executed atomically.

Instead of deleting 30 records then adding 20 new records in two operations,
batching lets you combine both tasks in a single operation. This removes the time during which an index
is in an inconsistent state and could be a great alternative to atomic
reindexing using a temporary index.

<Info>
  When updating large numbers of records, be aware of the [rate limitations](/doc/guides/scaling/algolia-service-limits#application-record-and-index-limits) on these processes and the [impact on your analytics data](/doc/guides/sending-and-managing-data/manage-indices-and-apps/manage-indices/concepts/indices-analytics). You'll know you've reached the rate limit when you start receiving errors. This can only be resolved if you wait before sending any further indexing operations.
</Info>

## Examples

### Batch write operations

<CodeGroup>
  ```cs C# theme={"system"}
    List<BatchOperation<Contact>> operations = new List<BatchOperation<Contact>>
    {
        new BatchOperation<Contact>
        {
          Action = BatchActionType.AddObject,
          IndexName = "index1",
          Body = new Contact { FirstName = "Jimmie", LastName = "Barninger" }
        },
        new BatchOperation<Contact>
        {
          Action = BatchActionType.UpdateObject,
          IndexName = "index1",
          Body = new Contact { ObjectID = "myID2", FirstName = "Max", LastName = "Barninger" }
        },
        new BatchOperation<Contact>
        {
          Action = BatchActionType.PartialUpdateObject,
          IndexName = "index1",
          Body = new Contact { ObjectID = "myID3", LastName = "McFarway" }
        },
        new BatchOperation<Contact>
        {
          Action = BatchActionType.PartialUpdateObjectNoCreate,
          IndexName = "index1",
          Body = new Contact { ObjectID = "myID4", LastName = "Warren" }
        },
        new BatchOperation<Contact>
        {
          Action = BatchActionType.DeleteObject,
          IndexName = "index2",
          Body = new Contact { ObjectID = "myID5" }
        }
    };

  client.MultipleBatch(operations);

  // Asynchronous
  client.MultipleBatchAsync(operations);
  ```

  ```go Go theme={"system"}
  type Contact struct {
      ObjectID  string `json:"objectID,omitempty"`
      Firstname string `json:"firstname,omitempty"`
      Lastname  string `json:"lastname,omitempty"`
  }

  operations := []search.BatchOperationIndexed{
      {
          IndexName: "index1",
          BatchOperation: search.BatchOperation{
              Action: search.AddObject,
              Body:   Contact{Firstname: "Jimmie", Lastname: "Barninger"},
          },
      },
      {
          IndexName: "index1",
          BatchOperation: search.BatchOperation{
              Action: search.UpdateObject,
              Body:   Contact{ObjectID: "myID2", Firstname: "Max", Lastname: "Barninger"},
          },
      },
      {
          IndexName: "index1",
          BatchOperation: search.BatchOperation{
              Action: search.PartialUpdateObject,
              Body:   Contact{ObjectID: "myID3", Lastname: "McFarway"},
          },
      },
      {
          IndexName: "index1",
          BatchOperation: search.BatchOperation{
              Action: search.PartialUpdateObjectNoCreate,
              Body:   Contact{ObjectID: "myID4", Firstname: "Warren"},
          },
      },
      {
          IndexName: "index2",
          BatchOperation: search.BatchOperation{
              Action: search.DeleteObject,
              Body:   Contact{ObjectID: "myID5"},
          },
      },
  }

  res, err := client.MultipleBatch(operations)
  ```

  ```java Java theme={"system"}
  List<BatchOperation<Contact>> operations =
  Arrays.asList(
      new BatchOperation<>(
          "index1", ActionEnum.ADD_OBJECT, 
          new Contact()
          .setFirstName("Jimmie")
          .setLastName("Barninger")),
      new BatchOperation<>(
          "index1", ActionEnum.UPDATE_OBJECT,
           new Contact()
           .setObjectID("myID2")
           .setFirstName("Max")
           .setLastName("Barninger")),
      new BatchOperation<>(
          "index1", ActionEnum.PARTIAL_UPDATE_OBJECT, 
          new Contact()
          .setObjectID("myID3")
          .setLastName("McFarway")),
      new BatchOperation<>(
          "index1", ActionEnum.PARTIAL_UPDATE_OBJECT_NO_CREATE, 
          new Contact()
          .setObjectID("myID4")
          .setFirstName("Warren")),
      new BatchOperation<>(
          "index2", ActionEnum.DELETE_OBJECT, 
          new Contact()
          .setObjectID("myID5")));

  // Async version
  client.multipleBatchAsync(operations);

  // Async version
  client.multipleBatchAsync(operations);
  ```

  ```js JavaScript theme={"system"}
  client.multipleBatch([
    {
      action: 'addObject',
      indexName: 'index1',
      body: {
        firstname: 'Jimmie',
        lastname: 'Barninger'
      }
    },
    {
      action: 'updateObject',
      indexName: 'index1',
      body: {
        objectID: 'myID2',
        firstname: 'Max',
        lastname: 'Barninger'
      }
    },
    {
      action: 'partialUpdateObject',
      indexName: 'index1',
      body: {
        objectID: 'myID3',
        lastname: 'McFarway'
      }
    },
    {
      action: 'partialUpdateObjectNoCreate',
      indexName: 'index1',
      body: {
        objectID: 'myID4',
        firstname: 'Warren'
      }
    },
    {
      action: 'deleteObject',
      indexName: 'index2',
      body: {
        objectID: 'myID5'
      }
    }
  ]).then(({ objectIDs }) => {
    console.log(objectIDs);
  });
  ```

  ```kotlin Kotlin theme={"system"}
  @Serializable
  data class Contact(
      val firstname: String,
      val lastname: String,
      override val objectID: ObjectID
  ) : Indexable

  val operations = listOf(
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.AddObject(
              json {
                  "firstname" to "Jimmie"
                  "lastname" to "Barninger"
              }
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.AddObject.from(
              serializer = Contact.serializer(),
              data = Contact("Jimmie", "Barninger", ObjectID("myID1"))
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.PartialUpdateObject.from(
              serializer = Contact.serializer(),
              data = Contact("Max", "Barninger", ObjectID("myID2"))
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.PartialUpdateObject.from(
              objectID = ObjectID("myID3"),
              partial = Partial.Update(Attribute("firstname"), "McFarway")
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.PartialUpdateObject.from(
              objectID = ObjectID("myID4"),
              partial = Partial.Update(Attribute("firstname"), "Warren"),
              createIfNotExists = false
          )
      ),
      BatchOperationIndex(
          indexName = indexName2,
          operation = BatchOperation.DeleteObject(ObjectID("myID5"))
      )
  )
  client.multipleBatchObjects(operations)
  ```

  ```php PHP theme={"system"}
  $res = $client->multipleBatch(
    [
      [
        'action'    => 'addObject',
        'indexName' => 'index1',
        'body'      => [
          'firstname' => 'Jimmie',
          'lastname'  => 'Barninger'
        ]
      ],
      [
        'action'    => 'updateObject',
        'indexName' => 'index1',
        'body'      => [
          'objectID' => 'myID2',
          'firstname' => 'Max',
          'lastname'  => 'Barninger'
        ]
      ],
      [
        'action'    => 'partialUpdateObject',
        'indexName' => 'index1',
        'body'      => [
          'objectID'  => 'myID3',
          'lastname'  => 'McFarway'
        ]
      ],
      [
        'action'    => 'partialUpdateObjectNoCreate',
        'indexName' => 'index1',
        'body'      => [
          'objectID'  => 'myID4',
          'firstname' => 'Warren'
        ]
      ],
      [
        'action'    => 'deleteObject',
        'indexName' => 'index2',
        'body'      => [
          'objectID'  => 'myID5'
        ]
      ]
    ]
  );
  ```

  ```python Python theme={"system"}
  client.multiple_batch([
      {
          'action': 'addObject',
          'indexName': 'index1',
          'body': {
              'firstname': 'Jimmie',
              'lastname': 'Barninger'
          }
      },
      {
          'action': 'updateObject',
          'indexName': 'index1',
          'body': {
              'objectID': 'myID2',
              'firstname': 'Max',
              'lastname': 'Barninger'
          }
      },
      {
          'action': 'partialUpdateObject',
          'indexName': 'index1',
          'body': {
              'objectID': 'myID3',
              'lastname': 'McFarway'
          }
      },
      {
          'action': 'partialUpdateObjectNoCreate',
          'indexName': 'index1',
          'body': {
              'objectID': 'myID4',
              'firstname': 'Warren'
          }
      },
      {
          'action': 'deleteObject',
          'indexName': 'index2',
          'body': {
              'objectID': 'myID5'
          }
      }
  ])
  ```

  ```ruby Ruby theme={"system"}
  res = client.batch([
    {
      'action': 'addObject',
      'indexName': 'index1',
      'body': {
        'firstname': 'Jimmie',
        'lastname': 'Barninger'
      }
    },
    {
      'action': 'updateObject',
      'indexName': 'index1',
      'body': {
        'objectID': 'myID2',
        'firstname': 'Max',
        'lastname': 'Barninger'
      }
    }
    {
      'action': 'partialUpdateObject',
      'indexName': 'index1',
      'body': {
        'objectID': 'myID3',
        'lastname': 'McFarway'
      }
    }
    {
      'action': 'partialUpdateObjectNoCreate',
      'indexName': 'index1',
      'body': {
        'objectID': 'myID4',
        'firstname': 'Warren'
      }
    }
    {
      'action': 'deleteObject',
      'indexName': 'index2',
      'body': {
        'objectID': 'myID5'
      }
    }
  ])
  ```

  ```scala Scala theme={"system"}
  client.execute {
    batch(
      index into "index1" `object` Contact("", "Jimmie", "Barninger"),
      index into "index1" `object` ContactWithObjectID("myID2", "Max", "Barninger"),
      partialUpdate from "index1" `object` ContactWithObjectID("myID3", "", "McFarway"),
      partialUpdate from "index1" `object` ContactWithObjectID("myID4", "Warren", "") createIfNotExists false,
      delete from "index2" objectId "myID5"
    )
  }
  ```

  ```swift Swift theme={"system"}
  struct Contact: Codable {
    let objectID: ObjectID
    let firstname: String
    let lastname: String
  }

  let operations: [(IndexName, BatchOperation)] = [
    ("index1", .add(Contact(objectID: "myID1", firstname: "Jimmie", lastname: "Barninger"))),
    ("index1", .update(objectID: "myID2", Contact(objectID: "myID2", firstname: "Max", lastname: "Barninger"))),
    ("index1", .partialUpdate(objectID: "myID3", ["lastname": "McFarway"] as JSON, createIfNotExists: true)),
    ("index1", .partialUpdate(objectID: "myID4", ["firstname": "Warren"] as JSON, createIfNotExists: false)),
    ("index2", .delete(objectID: "myID5"))
  ]

  client.multipleBatchObjects(operations: operations) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

### Batch write operations and send extra HTTP headers

<CodeGroup>
  ```cs C# theme={"system"}
  RequestOptions requestOptions = new RequestOptions
  {
      Headers = new Dictionary<string,string>{ { "X-Algolia-User-ID", "user123" } }
  };

    List<BatchOperation<Contact>> operations = new List<BatchOperation<Contact>>
    {
        new BatchOperation<Contact>
        {
          Action = BatchActionType.AddObject,
          IndexName = "index1",
          Body = new Contact { FirstName = "Jimmie", LastName = "Barninger" }
        },
        new BatchOperation<Contact>
        {
          Action = BatchActionType.AddObject,
          IndexName = "index1",
          Body = new Contact { FirstName = "Warren", LastName = "Speach" }
        }
    };

  client.MultipleBatch(operations, requestOptions);

  // Asynchronous
  client.MultipleBatchAsync(operations, requestOptions);
  ```

  ```go Go theme={"system"}
   contact := Contact{
      Firstname: "Jimmie",
      Lastname:  "Barninger",
  }

  operation := search.BatchOperation{Action: search.AddObject, Body: contact}

  operations := []search.BatchOperationIndexed{
      {IndexName: "prodIndex", BatchOperation: operation},
      {IndexName: "devIndex", BatchOperation: operation},
  }

  res, err := client.MultipleBatch(
      operations,
      opt.ExtraHeaders(map[string]string{"X-Algolia-User-ID": "userID2"}),
  )
  ```

  ```java Java theme={"system"}
  List<BatchOperation<Contact>> operations =
  Arrays.asList(
      new BatchOperation<>(
          "index1", ActionEnum.ADD_OBJECT, 
          new Contact()
          .setFirstName("Jimmie")
          .setLastName("Barninger")),
      new BatchOperation<>(
          "index2", ActionEnum.ADD_OBJECT, 
          new Contact()
          .setFirstName("Warren")
          .setLastName("Speach")));

  // Async version
  client.multipleBatchAsync(operations, 
    new RequestOptions().addExtraHeader("X-Algolia-User-ID", "user123"));

  // Async version
  client.multipleBatchAsync(operations, 
    new RequestOptions().addExtraHeader("X-Algolia-User-ID", "user123"));
  ```

  ```js JavaScript theme={"system"}
  client.multipleBatch([
      {
        action: 'addObject',
        indexName: 'index1',
        body: { firstname: 'Jimmie', lastname: 'Barninger' }
      },
      {
        action: 'addObject',
        indexName: 'index2',
        body: { firstname: 'Warren', lastname: 'Speach' }
      }
    ], {
      headers: {
        'X-Forwarded-For': '94.228.178.246'
      }
    }).then(({ objectIDs }) => {
      console.log(objectIDs);
    });
  ```

  ```kotlin Kotlin theme={"system"}
  @Serializable
  data class Contact(
      val firstname: String,
      val lastname: String,
      override val objectID: ObjectID
  ) : Indexable

  val operations = listOf(
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.AddObject(
              json {
                  "firstname" to "Jimmie"
                  "lastname" to "Barninger"
              }
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.AddObject.from(
              serializer = Contact.serializer(),
              data = Contact("Jimmie", "Barninger", ObjectID("myID1"))
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.PartialUpdateObject.from(
              serializer = Contact.serializer(),
              data = Contact("Max", "Barninger", ObjectID("myID2"))
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.PartialUpdateObject.from(
              objectID = ObjectID("myID3"),
              partial = Partial.Update(Attribute("firstname"), "McFarway")
          )
      ),
      BatchOperationIndex(
          indexName = indexName1,
          operation = BatchOperation.PartialUpdateObject.from(
              objectID = ObjectID("myID4"),
              partial = Partial.Update(Attribute("firstname"), "Warren"),
              createIfNotExists = false
          )
      ),
      BatchOperationIndex(
          indexName = indexName2,
          operation = BatchOperation.DeleteObject(ObjectID("myID5"))
      )
  )
  val requestOptions = requestOptions {
      headerAlgoliaUserId(UserID("user123"))
  }

  client.multipleBatchObjects(operations, requestOptions)
  ```

  ```php PHP theme={"system"}
  $operations = [
    [
      'action' => 'addObject',
      'indexName' => 'index1',
      'body' => [
        'firstname' => 'Jimmie',
        'lastname' => 'Barninger'
      ]
    ],
    [
      'action' => 'addObject',
      'indexName' => 'index2',
      'body' => [
        'firstname' => 'Warren',
        'lastname' => 'Speach'
      ]
    ]
  ];

  $res = $client->multipleBatch($operations, [
    'X-Forwarded-For' => '94.228.178.246'
  ]);
  ```

  ```python Python theme={"system"}
  operations = [
      {
          'action': 'addObject',
          'indexName': 'index1',
          'body': {'firstname': 'Jimmie', 'lastname': 'Barninger'}
      },
      {
          'action': 'addObject',
          'indexName': 'index2',
          'body': {'firstname': 'Warren', 'lastname': 'Speach'}
      }
  ]

  res = client.multiple_batch(operations, {
      'X-Forwarded-For': '94.228.178.246'
  })
  ```

  ```ruby Ruby theme={"system"}
  operations = [
   {
     'action': 'addObject',
     'indexName': 'index1',
     'body': {'firstname': 'Jimmie', 'lastname': 'Barninger'}
   },
   {
     'action': 'addObject',
     'indexName': 'index2',
     'body': {'firstname': 'Warren', 'lastname': 'Speach'}
   }
  ]

  res = client.batch(operations, {
    headers: {
      'X-Forwarded-For': '94.228.178.246'
    }
  })
  ```

  ```scala Scala theme={"system"}
  client.execute {
    batch(
      index into "index1" `object` Contact("Jimmie", "Barninger"),
      index into "index2" `object` Contact("Warren", "Speach")
    ) options RequestOptions(extraHeaders = Some(
      Map("X-Algolia-User-ID" => "user123"))
    )
  }
  ```

  ```swift Swift theme={"system"}
  var requestOptions = RequestOptions()
  requestOptions.headers["X-Algolia-User-ID"] = "user123"

  struct Contact: Codable {
    let objectID: ObjectID
    let firstname: String
    let lastname: String
  }

  let operations: [(IndexName, BatchOperation)] = [
    ("index1", .add(Contact(objectID: "myID1", firstname: "Jimmie", lastname: "Barninger"))),
    ("index2", .add(Contact(objectID: "myID2", firstname: "Warren", lastname: "Speach")))
  ]

  client.multipleBatchObjects(operations: operations, requestOptions: requestOptions) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

## Parameters

<ParamField body="operations" type="operation[]" required>
  List of operations.

  <Expandable>
    <ParamField body="action" type="string" required>
      Actions that need to be performed. It can be one of the following values:

      * `addObject`: add a record.
      * `updateObject`: add or replace an existing record. You must set the `objectID` attribute to indicate the record to update.
      * `partialUpdateObject`: partially update a record. You must set the `objectID` attribute to indicate the record to update.
      * `partialUpdateObjectNoCreate`: same as `partialUpdateObject`, except that the record isn't created if the `objectID` doesn't exist.
      * `deleteObject`: delete a record. You must set the `objectID` attribute to indicate the record to delete.
    </ParamField>

    <ParamField body="body" type="object" required>
      The JSON object with the information you need for
      the selected action.

      For example, `deleteObject`:

      ```json theme={"system"}
      {
        "objectID": "myID1"
      }
      ```
    </ParamField>

    <ParamField body="indexName" type="string" required>
      Index name to target.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="requestOptions" type="object">
  A mapping of request options to send along with the query.
</ParamField>

## Response

<ResponseField name="objectIDs" type="string[]">
  List of objectIDs affected by the batch of operations.
</ResponseField>

<ResponseField name="taskID" type="string[]">
  A list of taskIDs to use with the [`waitTask`](/doc/libraries/sdk/v1/methods/wait-task) method.
  One for each index.
</ResponseField>

### Response as JSON

This section shows the JSON response returned by the API.
Each API client wraps this response in language-specific objects, so the structure may vary.
To view the response, use the `getLogs` method.
Don't rely on the order of properties—JSON objects don't preserve key order.

```jsonc JSON icon=braces theme={"system"}
{
  "objectIDs": [
    "myObjectID1",
    "myObjectID2"
  ],
  "taskID": {
    "index1": 29866710291
  }
}
```
