---
layout: article
title: Bulk operations
description: Perform bulk operations on documents within your collections for efficient data handling.
---

Appwrite DocumentsDB supports bulk operations for documents, allowing you to create, update, or delete multiple documents in a single request. This can significantly improve performance for apps as it allows you to reduce the number of API calls needed while working with large data sets.

Bulk operations can only be performed via the server-side SDKs. The client-side SDKs do not support bulk operations by design to prevent abuse and protect against unexpected costs. This ensures that only trusted server environments can perform large-scale data operations.

For client applications that need bulk-like functionality, consider using [Appwrite Functions](/docs/products/functions) with proper rate limiting and validation.

**Important notes**

Bulk operations trigger Functions, Webhooks, or Realtime events for each document manipulated. Rather than a single event for the entire bulk operation, each document generates a separate event on the existing realtime channels for its operation type.

# Atomic behavior

Bulk operations in Appwrite are **atomic**, meaning they follow an all-or-nothing approach. Either all documents in your bulk request succeed, or all documents fail.

This atomicity ensures:
- **Data consistency**: Your database remains in a consistent state even if some operations would fail.
- **Race condition prevention**: Multiple clients can safely perform bulk operations simultaneously.
- **Simplified error handling**: You only need to handle complete success or complete failure scenarios.

For example, if you attempt to create 100 documents and one fails due to a validation error, none of the 100 documents will be created.

# Plan limits

Bulk operations have different limits based on your Appwrite plan:

| Plan | Documents per request |
|------|----------------------|
| Free | 100 |
| Pro | 1,000 |

These limits apply to all bulk operations including create, update, upsert, and delete operations. If you need higher limits than what the Pro plan offers, you can [inquire](/contact-us/enterprise) about a custom plan.

# Create documents

You can create multiple documents in a single request using the `createDocuments` method.

**Custom timestamps**

When creating, updating or upserting in bulk, you can set `$createdAt` and `$updatedAt` for each document in the payload. Values must be ISO 8601 date-time strings. If omitted, Appwrite sets them automatically.

```server-nodejs
const sdk = require('node-appwrite');

const client = new sdk.Client()
    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
    .setProject('<PROJECT_ID>')
    .setKey('<API_KEY>');

const documentsDB = new sdk.DocumentsDB(client);

const result = await documentsDB.createDocuments({
    databaseId: '<DATABASE_ID>',
    collectionId: '<COLLECTION_ID>',
    documents: [
        {
            $id: sdk.ID.unique(),
            name: 'Document 1'
        },
        {
            $id: sdk.ID.unique(),
            name: 'Document 2'
        }
    ]
});
```
```server-python
from appwrite.client import Client
from appwrite.services.documents_db import DocumentsDB
from appwrite.id import ID

client = Client()
client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
client.set_project('<PROJECT_ID>')
client.set_key('<API_KEY>')

documents_db = DocumentsDB(client)

result = documents_db.create_documents(
    database_id = '<DATABASE_ID>',
    collection_id = '<COLLECTION_ID>',
    documents = [
        {
            '$id': ID.unique(),
            'name': 'Document 1'
        },
        {
            '$id': ID.unique(),
            'name': 'Document 2'
        }
    ]
)
```
```server-deno
await documentsDB.createDocuments({
  databaseId: '<DATABASE_ID>',
  collectionId: '<COLLECTION_ID>',
  documents: [
    { $id: sdk.ID.unique(), name: 'Document 1' },
    { $id: sdk.ID.unique(), name: 'Document 2' }
  ]
});
```
```server-php
$documentsDB->createDocuments(
  databaseId: '<DATABASE_ID>',
  collectionId: '<COLLECTION_ID>',
  documents: [
    [ '$id' => ID::unique(), 'name' => 'Document 1' ],
    [ '$id' => ID::unique(), 'name' => 'Document 2' ]
  ]
);
```
```server-ruby
documents_db.create_documents(
  database_id: '<DATABASE_ID>',
  collection_id: '<COLLECTION_ID>',
  documents: [
    { '$id' => ID.unique(), 'name' => 'Document 1' },
    { '$id' => ID.unique(), 'name' => 'Document 2' }
  ]
)
```
```server-dotnet
await documentsDB.CreateDocuments(
  databaseId: "<DATABASE_ID>",
  collectionId: "<COLLECTION_ID>",
  documents: new List<Dictionary<string, object>>
  {
    new Dictionary<string, object>
    {
      ["$id"] = ID.Unique(),
      ["name"] = "Document 1"
    },
    new Dictionary<string, object>
    {
      ["$id"] = ID.Unique(),
      ["name"] = "Document 2"
    }
  }
);
```
```server-dart
await documentsDB.createDocuments(
  databaseId: '<DATABASE_ID>',
  collectionId: '<COLLECTION_ID>',
  documents: [
    { '\$id': ID.unique(), 'name': 'Document 1' },
    { '\$id': ID.unique(), 'name': 'Document 2' }
  ]
);
```
```server-swift
try await documentsDB.createDocuments(
  databaseId: "<DATABASE_ID>",
  collectionId: "<COLLECTION_ID>",
  documents: [
    ["$id": ID.unique(), "name": "Document 1"],
    ["$id": ID.unique(), "name": "Document 2"]
  ]
)
```
```server-kotlin
documentsDB.createDocuments(
  databaseId = "<DATABASE_ID>",
  collectionId = "<COLLECTION_ID>",
  documents = listOf(
    mapOf("\$id" to ID.unique(), "name" to "Document 1"),
    mapOf("\$id" to ID.unique(), "name" to "Document 2")
  )
)
```
```server-java
documentsDB.createDocuments(
  "<DATABASE_ID>",
  "<COLLECTION_ID>",
  Arrays.asList(
    Map.of(
      "$id", ID.unique(),
      "name", "Document 1"
    ),
    Map.of(
      "$id", ID.unique(),
      "name", "Document 2"
    )
  ),
  new CoroutineCallback<>((result, error) -> {
    if (error != null) {
      error.printStackTrace();
      return null;
    }
    System.out.println(result);
    return null;
  })
);
```
```rust
use appwrite::Client;
use appwrite::services::documents_db::DocumentsDB;
use appwrite::id::ID;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new()
        .set_endpoint("https://<REGION>.cloud.appwrite.io/v1")
        .set_project("<PROJECT_ID>")
        .set_key("<API_KEY>");

    let documents_db = DocumentsDB::new(&client);

    let result = documents_db.create_documents(
        "<DATABASE_ID>",
        "<COLLECTION_ID>",
        vec![
            json!({
                "$id": ID::unique(),
                "name": "Document 1"
            }),
            json!({
                "$id": ID::unique(),
                "name": "Document 2"
            }),
        ],
        None,
    ).await?;

    Ok(())
}
```

# Update documents

**Permissions required**

You must grant **update** permissions to users at the **collection level** before users can update documents.
[Learn more about permissions](/docs/products/databases/documentsdb/permissions)

You can update multiple documents in a single request using the `updateDocuments` method.

```server-nodejs
const sdk = require('node-appwrite');

const client = new sdk.Client()
    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
    .setProject('<PROJECT_ID>')
    .setKey('<API_KEY>');

const documentsDB = new sdk.DocumentsDB(client);

const result = await documentsDB.updateDocuments({
    databaseId: '<DATABASE_ID>',
    collectionId: '<COLLECTION_ID>',
    data: {
        status: 'published'
    },
    queries: [
        sdk.Query.equal('status', 'draft')
    ]
});
```

```server-python
from appwrite.client import Client
from appwrite.services.documents_db import DocumentsDB
from appwrite.query import Query

client = Client()
client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
client.set_project('<PROJECT_ID>')
client.set_key('<API_KEY>')

documents_db = DocumentsDB(client)

result = documents_db.update_documents(
    database_id = '<DATABASE_ID>',
    collection_id = '<COLLECTION_ID>',
    data = {
        'status': 'published'
    },
    queries = [
        Query.equal('status', 'draft')
    ]
)
```

```rust
use appwrite::Client;
use appwrite::services::documents_db::DocumentsDB;
use appwrite::query::Query;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new()
        .set_endpoint("https://<REGION>.cloud.appwrite.io/v1")
        .set_project("<PROJECT_ID>")
        .set_key("<API_KEY>");

    let documents_db = DocumentsDB::new(&client);

    let result = documents_db.update_documents(
        "<DATABASE_ID>",
        "<COLLECTION_ID>",
        Some(json!({
            "status": "published"
        })),
        Some(vec![
            Query::equal("status", "draft").to_string(),
        ]),
        None,
    ).await?;

    Ok(())
}
```

# Upsert documents

**Permissions required**

You must grant **create** and **update** permissions to users at the **collection level** before users can create documents.
[Learn more about permissions](/docs/products/databases/documentsdb/permissions)

You can upsert multiple documents in a single request using the `upsertDocuments` method.

```server-nodejs
const sdk = require('node-appwrite');

const client = new sdk.Client()
    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
    .setProject('<PROJECT_ID>')
    .setKey('<API_KEY>');

const documentsDB = new sdk.DocumentsDB(client);

const result = await documentsDB.upsertDocuments({
    databaseId: '<DATABASE_ID>',
    collectionId: '<COLLECTION_ID>',
    documents: [
        {
            $id: sdk.ID.unique(),
            name: 'New Document 1'
        },
        {
            $id: 'document-id-2', // Existing document ID
            name: 'New Document 2'
        }
    ]
});
```

```server-python
from appwrite.client import Client
from appwrite.services.documents_db import DocumentsDB
from appwrite.id import ID

client = Client()
client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
client.set_project('<PROJECT_ID>')
client.set_key('<API_KEY>')

documents_db = DocumentsDB(client)

result = documents_db.upsert_documents(
    database_id = '<DATABASE_ID>',
    collection_id = '<COLLECTION_ID>',
    documents = [
        {
            '$id': ID.unique(),
            'name': 'New Document 1'
        },
        {
            '$id': 'document-id-2',  # Existing document ID
            'name': 'New Document 2'
        }
    ]
)
```

```rust
use appwrite::Client;
use appwrite::services::documents_db::DocumentsDB;
use appwrite::id::ID;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new()
        .set_endpoint("https://<REGION>.cloud.appwrite.io/v1")
        .set_project("<PROJECT_ID>")
        .set_key("<API_KEY>");

    let documents_db = DocumentsDB::new(&client);

    let result = documents_db.upsert_documents(
        "<DATABASE_ID>",
        "<COLLECTION_ID>",
        vec![
            json!({
                "$id": ID::unique(),
                "name": "New Document 1"
            }),
            json!({
                "$id": "document-id-2", // Existing document ID
                "name": "New Document 2"
            }),
        ],
        None,
    ).await?;

    Ok(())
}
```

# Delete documents

**Permissions required**

You must grant **delete** permissions to users at the **collection level** before users can delete documents.
[Learn more about permissions](/docs/products/databases/documentsdb/permissions)

You can delete multiple documents in a single request using the `deleteDocuments` method.

```server-nodejs
const sdk = require('node-appwrite');

const client = new sdk.Client()
    .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
    .setProject('<PROJECT_ID>')
    .setKey('<API_KEY>');

const documentsDB = new sdk.DocumentsDB(client);

const result = await documentsDB.deleteDocuments({
    databaseId: '<DATABASE_ID>',
    collectionId: '<COLLECTION_ID>',
    queries: [
        sdk.Query.equal('status', 'archived')
    ]
});
```

```server-python
from appwrite.client import Client
from appwrite.services.documents_db import DocumentsDB
from appwrite.query import Query

client = Client()
client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
client.set_project('<PROJECT_ID>')
client.set_key('<API_KEY>')

documents_db = DocumentsDB(client)

result = documents_db.delete_documents(
    database_id = '<DATABASE_ID>',
    collection_id = '<COLLECTION_ID>',
    queries = [
        Query.equal('status', 'archived')
    ]
)
```

```rust
use appwrite::Client;
use appwrite::services::documents_db::DocumentsDB;
use appwrite::query::Query;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new()
        .set_endpoint("https://<REGION>.cloud.appwrite.io/v1")
        .set_project("<PROJECT_ID>")
        .set_key("<API_KEY>");

    let documents_db = DocumentsDB::new(&client);

    let result = documents_db.delete_documents(
        "<DATABASE_ID>",
        "<COLLECTION_ID>",
        Some(vec![
            Query::equal("status", "archived").to_string(),
        ]),
        None,
    ).await?;

    Ok(())
}
```

**Queries for deletion**

When deleting documents, you must specify queries to filter which documents to delete.
If no queries are provided, all documents in the collection will be deleted.
[Learn more about queries](/docs/products/databases/documentsdb/queries).

# Use transactions

All bulk operations accept `transactionId`. When provided, Appwrite stages the bulk request and applies it on commit. See [Transactions](/docs/products/databases/documentsdb/transactions).

```server-nodejs
await documentsDB.createDocuments({
  databaseId: '<DATABASE_ID>',
  collectionId: '<COLLECTION_ID>',
  documents: [
    { $id: sdk.ID.unique(), name: 'One' },
    { $id: sdk.ID.unique(), name: 'Two' }
  ],
  transactionId: '<TRANSACTION_ID>'
});
```
```server-python
documents_db.create_documents(
  database_id = '<DATABASE_ID>',
  collection_id = '<COLLECTION_ID>',
  documents = [
    { '$id': ID.unique(), 'name': 'One' },
    { '$id': ID.unique(), 'name': 'Two' }
  ],
  transaction_id = '<TRANSACTION_ID>'
)
```
```server-deno
await documentsDB.createDocuments({
  databaseId: '<DATABASE_ID>',
  collectionId: '<COLLECTION_ID>',
  documents: [
    { $id: sdk.ID.unique(), name: 'One' },
    { $id: sdk.ID.unique(), name: 'Two' }
  ],
  transactionId: '<TRANSACTION_ID>'
});
```
```server-php
$documentsDB->createDocuments(
  databaseId: '<DATABASE_ID>',
  collectionId: '<COLLECTION_ID>',
  documents: [
    [ '$id' => ID::unique(), 'name' => 'One' ],
    [ '$id' => ID::unique(), 'name' => 'Two' ]
  ],
  transactionId: '<TRANSACTION_ID>'
);
```
```server-ruby
documents_db.create_documents(
  database_id: '<DATABASE_ID>',
  collection_id: '<COLLECTION_ID>',
  documents: [
    { '$id' => ID.unique(), 'name' => 'One' },
    { '$id' => ID.unique(), 'name' => 'Two' }
  ],
  transaction_id: '<TRANSACTION_ID>'
)
```
```server-dotnet
await documentsDB.CreateDocuments(
  databaseId: "<DATABASE_ID>",
  collectionId: "<COLLECTION_ID>",
  documents: new List<Dictionary<string, object>>
  {
    new Dictionary<string, object>
    {
      ["$id"] = ID.Unique(),
      ["name"] = "One"
    },
    new Dictionary<string, object>
    {
      ["$id"] = ID.Unique(),
      ["name"] = "Two"
    }
  },
  transactionId: "<TRANSACTION_ID>"
);
```
```server-dart
await documentsDB.createDocuments(
  databaseId: '<DATABASE_ID>',
  collectionId: '<COLLECTION_ID>',
  documents: [
    { '\$id': ID.unique(), 'name': 'One' },
    { '\$id': ID.unique(), 'name': 'Two' }
  ],
  transactionId: '<TRANSACTION_ID>'
);
```
```server-swift
try await documentsDB.createDocuments(
  databaseId: "<DATABASE_ID>",
  collectionId: "<COLLECTION_ID>",
  documents: [
    ["$id": ID.unique(), "name": "One"],
    ["$id": ID.unique(), "name": "Two"]
  ],
  transactionId: "<TRANSACTION_ID>"
)
```
```server-kotlin
documentsDB.createDocuments(
  databaseId = "<DATABASE_ID>",
  collectionId = "<COLLECTION_ID>",
  documents = listOf(
    mapOf("\$id" to ID.unique(), "name" to "One"),
    mapOf("\$id" to ID.unique(), "name" to "Two")
  ),
  transactionId = "<TRANSACTION_ID>"
)
```
```server-java
documentsDB.createDocuments(
  "<DATABASE_ID>",
  "<COLLECTION_ID>",
  Arrays.asList(
    Map.of(
      "$id", ID.unique(),
      "name", "One"
    ),
    Map.of(
      "$id", ID.unique(),
      "name", "Two"
    )
  ),
  "<TRANSACTION_ID>",
  new CoroutineCallback<>((result, error) -> {
    if (error != null) {
      error.printStackTrace();
      return null;
    }
    System.out.println(result);
    return null;
  })
);
```
```rust
let result = documents_db.create_documents(
    "<DATABASE_ID>",
    "<COLLECTION_ID>",
    vec![
        json!({
            "$id": ID::unique(),
            "name": "One"
        }),
        json!({
            "$id": ID::unique(),
            "name": "Two"
        }),
    ],
    Some("<TRANSACTION_ID>"),
).await?;
```
