---
layout: article
title: Transactions
description: Stage multiple database operations and commit them atomically. Group changes across databases and tables with ordering, isolation, and conflict detection.
---

Transactions let you stage multiple database operations and apply them together, atomically. Use transactions to keep related changes consistent, even when they span multiple databases and tables.

# How transactions work {% #how-transactions-work %}

1. Call the [createTransaction](#create-a-transaction) method to create a transaction. This will return a transaction model, including its ID.
2. Stage operations by passing the `transactionId` parameter to supported row, bulk, and atomic numeric methods. You can stage many operations at once with the [createOperations](#create-operations) method.
3. Call the [updateTransaction](#update-transaction) method to commit or roll back.

On commit, Appwrite replays all staged logs in order inside a real database transaction. Staged operations see earlier staged changes (read your own writes). If any affected row changed outside your transaction, the commit fails with a conflict.

{% info title="Scope and limitations" %}
You can stage operations across any database and table within the same transaction. Schema operations (for example, adding or removing columns) are not included in transactions.
{% /info %}

# Limits {% #limits %}

The maximum number of operations you can stage per transaction depends on your plan:

| Plan | Max operations per transaction |
|------|-------------------------------|
| Free | 100 |
| Pro | 1,000 |
| Scale | 2,500 |

# Create a transaction {% #create-a-transaction %}

Call the `createTransaction` method to begin. It returns a transaction model that includes `$id`. Pass this ID as `transactionId` to subsequent operations.

{% multicode %}
```client-web
import { Client, TablesDB } from 'appwrite';

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

const tablesDB = new TablesDB(client);

const tx = await tablesDB.createTransaction();
// tx.$id is your transactionId
```
```client-react-native
import { Client, TablesDB } from 'react-native-appwrite';

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

const tablesDB = new TablesDB(client);

const tx = await tablesDB.createTransaction();
// tx.$id is your transactionId
```
```client-flutter
import 'package:appwrite/appwrite.dart';

final client = Client()
  .setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
  .setProject('<PROJECT_ID>');

final tablesDB = TablesDB(client);

final tx = await tablesDB.createTransaction();
// tx.$id is your transactionId
```
```client-apple
import Appwrite

let client = Client()
  .setEndpoint("https://<REGION>.cloud.appwrite.io/v1")
  .setProject("<PROJECT_ID>")

let tablesDB = TablesDB(client)

let tx = try await tablesDB.createTransaction()
// tx.$id is your transactionId
```
```client-android-kotlin
import io.appwrite.Client
import io.appwrite.services.TablesDB

val client = Client(applicationContext)
  .setEndpoint("https://<REGION>.cloud.appwrite.io/v1")
  .setProject("<PROJECT_ID>")

val tablesDB = TablesDB(client)

val tx = tablesDB.createTransaction()
// tx.$id is your transactionId
```
```client-android-java
import io.appwrite.Client;
import io.appwrite.services.TablesDB;

Client client = new Client()
    .setEndpoint("https://<REGION>.cloud.appwrite.io/v1")
    .setProject("<PROJECT_ID>");

TablesDB tablesDB = new TablesDB(client);

// Create a transaction (asynchronous)
tablesDB.createTransaction(new CoroutineCallback<>((tx, error) -> {
  if (error != null) {
    error.printStackTrace();
    return;
  }
  System.out.println(tx);
}));
```
```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 tablesDB = new sdk.TablesDB(client);

const tx = await tablesDB.createTransaction();
// tx.$id is your transactionId
```
```server-deno
import * as sdk from 'npm:node-appwrite';

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

const tablesDB = new sdk.TablesDB(client);

const tx = await tablesDB.createTransaction();
// tx.$id is your transactionId
```
```server-python
from appwrite.client import Client
from appwrite.services.tables_db import TablesDB

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

tablesDB = TablesDB(client)

tx = tablesDB.create_transaction()
# tx.$id is your transactionId
```
```server-php
<?php

use Appwrite\Client;
use Appwrite\Services\TablesDB;

$client = new Client();

$client
  ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
  ->setProject('<PROJECT_ID>')
  ->setKey('<API_KEY>')
;

$tablesDB = new TablesDB($client);

$tx = $tablesDB->createTransaction();
// $tx->\$id is your transactionId
```
```server-ruby
require 'appwrite'

include Appwrite

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

tablesDB = TablesDB.new(client)

tx = tablesDB.create_transaction
# tx['$id'] is your transactionId
```
```server-dotnet
using Appwrite;
using Appwrite.Services;

var client = new Client()
  .SetEndPoint("https://<REGION>.cloud.appwrite.io/v1")
  .SetProject("<PROJECT_ID>")
  .SetKey("<API_KEY>");

var tablesDB = new TablesDB(client);

var tx = await tablesDB.CreateTransaction();
// tx.$id is your transactionId
```
```server-dart
import 'package:dart_appwrite/dart_appwrite.dart';

void main() async {
  Client client = Client();
  TablesDB tablesDB = TablesDB(client);

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

  final tx = await tablesDB.createTransaction();
  // tx contains the transaction ID
}
```
```server-go
package main

import (
  "log"
  "github.com/appwrite/sdk-for-go/appwrite"
)

func main() {
  client := appwrite.NewClient(
    appwrite.WithEndpoint("https://<REGION>.cloud.appwrite.io/v1"),
    appwrite.WithProject("<PROJECT_ID>"),
    appwrite.WithKey("<API_KEY>"),
  )

  tablesDB := appwrite.NewTablesDB(client)

  tx, err := tablesDB.CreateTransaction()
  if err != nil { log.Fatal(err) }
  _ = tx
}
```
```server-swift
import Appwrite

let client = Client()
  .setEndpoint("https://<REGION>.cloud.appwrite.io/v1")
  .setProject("<PROJECT_ID>")
  .setKey("<API_KEY>")

let tablesDB = TablesDB(client)

let tx = try await tablesDB.createTransaction()
// tx.$id is your transactionId
```
```server-kotlin
import io.appwrite.Client
import io.appwrite.services.TablesDB

val client = Client()
  .setEndpoint("https://<REGION>.cloud.appwrite.io/v1")
  .setProject("<PROJECT_ID>")
  .setKey("<API_KEY>")

val tablesDB = TablesDB(client)

val tx = tablesDB.createTransaction()
// tx.$id is your transactionId
```
```server-java
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.TablesDB;

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

TablesDB tablesDB = new TablesDB(client);

tablesDB.createTransaction(new CoroutineCallback<>((result, error) -> {
  if (error != null) {
    error.printStackTrace();
    return;
  }
  System.out.println(result);
}));
```
```server-rust
use appwrite::Client;
use appwrite::services::tables_db::TablesDB;

#[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 tables_db = TablesDB::new(&client);

    let tx = tables_db.create_transaction(None).await?;
    // tx.id is your transaction_id

    Ok(())
}
```
{% /multicode %}

# Stage operations {% #stage-operations %}

Add the `transactionId` parameter to supported methods to stage them instead of immediately persisting.

When you pass `transactionId`, Appwrite writes the operation to an internal staging area. The target table is not modified until you commit the transaction.

## Stage single operations {% #stage-single-operations %}

Create, update, upsert, delete, and atomic numeric operations accept `transactionId`, as well as their bulk versions (createRows, updateRows, upsertRows, deleteRows).

{% multicode %}
```client-web
// Create inside a transaction
await tablesDB.createRow({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  data: { name: 'Walter' },
  transactionId: tx.$id
});

// Increment inside a transaction
await tablesDB.incrementRowColumn({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  column: 'credits',
  value: 1,
  transactionId: tx.$id
});
```
```client-flutter
// Create inside a transaction
await tablesDB.createRow(
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  data: { 'name': 'Walter' },
  transactionId: tx.$id
);

// Increment inside a transaction
await tablesDB.incrementRowColumn(
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  column: 'credits',
  value: 1,
  transactionId: tx.$id
);
```
```client-apple
// Create inside a transaction
try await tablesDB.createRow(
  databaseId: "<DATABASE_ID>",
  tableId: "<TABLE_ID>",
  rowId: "<ROW_ID>",
  data: ["name": "Walter"],
  transactionId: tx.$id
)

// Increment inside a transaction
try await tablesDB.incrementRowColumn(
  databaseId: "<DATABASE_ID>",
  tableId: "<TABLE_ID>",
  rowId: "<ROW_ID>",
  column: "credits",
  value: 1,
  transactionId: tx.$id
)
```
```server-kotlin
// Create inside a transaction
tablesDB.createRow(
  databaseId = "<DATABASE_ID>",
  tableId = "<TABLE_ID>",
  rowId = "<ROW_ID>",
  data = mapOf("name" to "Walter"),
  transactionId = tx.$id
)

// Increment inside a transaction
tablesDB.incrementRowColumn(
  databaseId = "<DATABASE_ID>",
  tableId = "<TABLE_ID>",
  rowId = "<ROW_ID>",
  column = "credits",
  value = 1,
  transactionId = tx.$id
)
```
```server-java
// Create inside a transaction (asynchronous)
tablesDB.createRow(
  "<DATABASE_ID>",
  "<TABLE_ID>",
  "<ROW_ID>",
  Map.of("name", "Walter"),
  "<TRANSACTION_ID>",
  new CoroutineCallback<>((row, error) -> {
    if (error != null) {
      error.printStackTrace();
      return null;
    }
    System.out.println(row);
    return null;
  })
);

// Increment inside a transaction (asynchronous)
tablesDB.incrementRowColumn(
  "<DATABASE_ID>",
  "<TABLE_ID>",
  "<ROW_ID>",
  "credits",
  1,
  "<TRANSACTION_ID>",
  new CoroutineCallback<>((row, error) -> {
    if (error != null) {
      error.printStackTrace();
      return null;
    }
    System.out.println(row);
    return null;
  })
);
```
```client-react-native
// Create inside a transaction
await tablesDB.createRow({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  data: { name: 'Walter' },
  transactionId: tx.$id
});

// Increment inside a transaction
await tablesDB.incrementRowColumn({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  column: 'credits',
  value: 1,
  transactionId: tx.$id
});
```
```server-nodejs
// Update inside a transaction
await tablesDB.updateRow({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  data: { plan: 'pro' },
  transactionId: tx.$id
});

// Delete inside a transaction
await tablesDB.deleteRow({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  transactionId: tx.$id
});
```
```server-python
# Upsert inside a transaction
tablesDB.upsert_row(
  database_id = '<DATABASE_ID>',
  table_id = '<TABLE_ID>',
  row_id = '<ROW_ID>',
  data = { 'name': 'Walter' },
  transaction_id = tx.id
)

# Decrement inside a transaction
tablesDB.decrement_row_column(
  database_id = '<DATABASE_ID>',
  table_id = '<TABLE_ID>',
  row_id = '<ROW_ID>',
  column = 'credits',
  value = 1,
  transaction_id = tx.id
)
```
```server-php
// Create inside a transaction
$tablesDB->createRow(
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  data: ['name' => 'Walter'],
  transactionId: $tx['$id']
);

// Increment inside a transaction
$tablesDB->incrementRowColumn(
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  column: 'credits',
  value: 1,
  transactionId: $tx['$id']
);
```
```server-ruby
# Create inside a transaction
tablesDB.create_row(
  database_id: '<DATABASE_ID>',
  table_id: '<TABLE_ID>',
  row_id: '<ROW_ID>',
  data: { 'name' => 'Walter' },
  transaction_id: tx['$id']
)

# Increment inside a transaction
tablesDB.increment_row_column(
  database_id: '<DATABASE_ID>',
  table_id: '<TABLE_ID>',
  row_id: '<ROW_ID>',
  column: 'credits',
  value: 1,
  transaction_id: tx['$id']
)
```
```server-dotnet
// Create inside a transaction
await tablesDB.CreateRow(
  databaseId: "<DATABASE_ID>",
  tableId: "<TABLE_ID>",
  rowId: "<ROW_ID>",
  data: new Dictionary<string, object> { ["name"] = "Walter" },
  transactionId: tx.Id
);

// Increment inside a transaction
await tablesDB.IncrementRowColumn(
  databaseId: "<DATABASE_ID>",
  tableId: "<TABLE_ID>",
  rowId: "<ROW_ID>",
  column: "credits",
  value: 1,
  transactionId: tx.Id
);
```
```server-dart
// Create inside a transaction
await tablesDB.createRow(
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  data: { 'name': 'Walter' },
  transactionId: tx.Id
);

// Increment inside a transaction
await tablesDB.incrementRowColumn(
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  column: 'credits',
  value: 1,
  transactionId: tx.Id
);
```
```server-deno
// Create inside a transaction
await tablesDB.createRow({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  data: { name: 'Walter' },
  transactionId: tx.$id
});

// Increment inside a transaction
await tablesDB.incrementRowColumn({
  databaseId: '<DATABASE_ID>',
  tableId: '<TABLE_ID>',
  rowId: '<ROW_ID>',
  column: 'credits',
  value: 1,
  transactionId: tx.$id
});
```
```server-swift
// Create inside a transaction
try await tablesDB.createRow(
  databaseId: "<DATABASE_ID>",
  tableId: "<TABLE_ID>",
  rowId: "<ROW_ID>",
  data: ["name": "Walter"],
  transactionId: tx.$id
)

// Increment inside a transaction
try await tablesDB.incrementRowColumn(
  databaseId: "<DATABASE_ID>",
  tableId: "<TABLE_ID>",
  rowId: "<ROW_ID>",
  column: "credits",
  value: 1,
  transactionId: tx.$id
)
```
```server-rust
use appwrite::Client;
use appwrite::services::tables_db::TablesDB;
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 tables_db = TablesDB::new(&client);

    let tx = tables_db.create_transaction(None).await?;

    // Update inside a transaction
    tables_db.update_row(
        "<DATABASE_ID>",
        "<TABLE_ID>",
        "<ROW_ID>",
        Some(json!({ "plan": "pro" })),
        None,
        Some(&tx.id),
    ).await?;

    // Delete inside a transaction
    tables_db.delete_row(
        "<DATABASE_ID>",
        "<TABLE_ID>",
        "<ROW_ID>",
        Some(&tx.id),
    ).await?;

    Ok(())
}
```
{% /multicode %}

## Stage many with createOperations {% #create-operations %}

Use the `createOperations` method to stage multiple operations across databases and tables in a single request. Provide an array of operation objects:

```json
[
  {
    "action": "create|update|upsert|increment|decrement|delete|bulkCreate|bulkUpdate|bulkUpsert|bulkDelete",
    "databaseId": "<DATABASE_ID>",
    "tableId|collectionId": "<TABLE_ID|COLLECTION_ID>",
    "rowId|documentId": "<ROW_ID|DOCUMENT_ID>",
    "data": {}
  }
]
```

### Provide data for each action (createOperations) {% #provide-data-for-each-action %}

### Create, update, and upsert {% #create-update-upsert %}
Pass a raw data object.
```json
{ "name": "Walter" }
```

### Increment and decrement {% #increment-decrement %}
Pass a value and optionally `min`/`max` bounds.
```json
{ "value": 1, "min": 0, "max": 1000, "column": "<COLUMN_NAME>" }
```

### Bulk create and bulk upsert {% #bulk-create-upsert %}
Pass an array of raw data objects.
```json
[{ "$id": "123", "name": "Walter" }]
```

### Bulk update {% #bulk-update %}
Pass queries and the data to apply.
```json
{ "queries": [{"method": "equal", "attribute": "status", "values": ["draft"]}], "data": { "status": "published" } }
```

### Bulk delete {% #bulk-delete %}
Pass queries to select rows to delete.
```json
{ "queries": [{"method": "equal", "attribute": "archived", "values": [true]}] }
```

{% multicode %}
```server-nodejs
// Stage multiple operations at once
await tablesDB.createOperations({
  transactionId: tx.$id,
  operations: [
    {
      action: 'create',
      databaseId: '<DB_A>',
      tableId: '<TABLE_1>',
      rowId: 'u1',
      data: { name: 'Walter' }
    },
    {
      action: 'increment',
      databaseId: '<DB_B>',
      tableId: '<TABLE_2>',
      rowId: 'u2',
      data: { value: 1, min: 0, column: 'credits' }
    }
  ]
});
```
```server-python
tablesDB.create_operations(
  transaction_id = tx.id,
  operations = [
    {
      'action': 'create',
      'databaseId': '<DB_A>',
      'tableId': '<TABLE_1>',
      'rowId': 'u1',
      'data': { 'name': 'Walter' }
    },
    {
      'action': 'increment',
      'databaseId': '<DB_B>',
      'tableId': '<TABLE_2>',
      'rowId': 'u2',
      'data': { 'value': 1, 'min': 0, 'column': 'credits' }
    }
  ]
)
```
```client-web
await tablesDB.createOperations({
  transactionId: tx.$id,
  operations: [
    {
      action: 'create',
      databaseId: '<DB_A>',
      tableId: '<TABLE_1>',
      rowId: 'u1',
      data: { name: 'Walter' }
    },
    {
      action: 'increment',
      databaseId: '<DB_B>',
      tableId: '<TABLE_2>',
      rowId: 'u2',
      data: { value: 1, min: 0, column: 'credits' }
    }
  ]
});
```
```client-flutter
await tablesDB.createOperations(
  transactionId: tx.$id,
  operations: [
    {
      'action': 'create',
      'databaseId': '<DB_A>',
      'tableId': '<TABLE_1>',
      'rowId': 'u1',
      'data': { 'name': 'Walter' }
    },
    {
      'action': 'increment',
      'databaseId': '<DB_B>',
      'tableId': '<TABLE_2>',
      'rowId': 'u2',
      'data': { 'value': 1, 'min': 0, 'column': 'credits' }
    }
  ],
);
```
```client-apple
try await tablesDB.createOperations(
  transactionId: tx.$id,
  operations: [
    [
      "action": "create",
      "databaseId": "<DB_A>",
      "tableId": "<TABLE_1>",
      "rowId": "u1",
      "data": ["name": "Walter"]
    ],
    [
      "action": "increment",
      "databaseId": "<DB_B>",
      "tableId": "<TABLE_2>",
      "rowId": "u2",
      "data": ["value": 1, "min": 0, "column": "credits"]
    ]
  ]
)
```
```server-kotlin
tablesDB.createOperations(
  transactionId = tx.$id,
  operations = listOf(
    mapOf(
      "action" to "create",
      "databaseId" to "<DB_A>",
      "tableId" to "<TABLE_1>",
      "rowId" to "u1",
      "data" to mapOf("name" to "Walter")
    ),
    mapOf(
      "action" to "increment",
      "databaseId" to "<DB_B>",
      "tableId" to "<TABLE_2>",
      "rowId" to "u2",
      "data" to mapOf("value" to 1, "min" to 0, "column" to "credits")
    )
  )
)
```
```server-java
// Stage multiple operations at once (asynchronous)
List<Map<String, Object>> operations = Arrays.asList(
  Map.of(
    "action", "create",
    "databaseId", "<DB_A>",
    "tableId", "<TABLE_1>",
    "rowId", "u1",
    "data", Map.of("name", "Walter")
  ),
  Map.of(
    "action", "increment",
    "databaseId", "<DB_B>",
    "tableId", "<TABLE_2>",
    "rowId", "u2",
    "data", Map.of("value", 1, "min", 0, "column", "credits")
  )
);

tablesDB.createOperations(
  "<TRANSACTION_ID>",
  operations,
  new CoroutineCallback<>((result, error) -> {
    if (error != null) {
      error.printStackTrace();
      return null;
    }
    System.out.println(result);
    return null;
  })
);
```
```client-react-native
await tablesDB.createOperations({
  transactionId: tx.$id,
  operations: [
    {
      action: 'create',
      databaseId: '<DB_A>',
      tableId: '<TABLE_1>',
      rowId: 'u1',
      data: { name: 'Walter' }
    },
    {
      action: 'increment',
      databaseId: '<DB_B>',
      tableId: '<TABLE_2>',
      rowId: 'u2',
      data: { value: 1, min: 0, column: 'credits' }
    }
  ]
});
```
```server-deno
await tablesDB.createOperations({
  transactionId: tx.$id,
  operations: [
    {
      action: 'create',
      databaseId: '<DB_A>',
      tableId: '<TABLE_1>',
      rowId: 'u1',
      data: { name: 'Walter' }
    },
    {
      action: 'increment',
      databaseId: '<DB_B>',
      tableId: '<TABLE_2>',
      rowId: 'u2',
      data: { value: 1, min: 0, column: 'credits' }
    }
  ]
});
```
```server-php
$tablesDB->createOperations(
  transactionId: $tx['$id'],
  operations: [
    [
      'action' => 'create',
      'databaseId' => '<DB_A>',
      'tableId' => '<TABLE_1>',
      'rowId' => 'u1',
      'data' => [ 'name' => 'Walter' ]
    ],
    [
      'action' => 'increment',
      'databaseId' => '<DB_B>',
      'tableId' => '<TABLE_2>',
      'rowId' => 'u2',
      'data' => [ 'value' => 1, 'min' => 0, 'column' => 'credits' ]
    ]
  ]
);
```
```server-ruby
tablesDB.create_operations(
  transaction_id: tx['$id'],
  operations: [
    {
      'action' => 'create',
      'databaseId' => '<DB_A>',
      'tableId' => '<TABLE_1>',
      'rowId' => 'u1',
      'data' => { 'name' => 'Walter' }
    },
    {
      'action' => 'increment',
      'databaseId' => '<DB_B>',
      'tableId' => '<TABLE_2>',
      'rowId' => 'u2',
      'data' => { 'value' => 1, 'min' => 0, 'column' => 'credits' }
    }
  ]
)
```
```server-dotnet
await tablesDB.CreateOperations(
  transactionId: tx.Id,
  operations: new List<Dictionary<string, object>>
  {
    new Dictionary<string, object>
    {
      ["action"] = "create",
      ["databaseId"] = "<DB_A>",
      ["tableId"] = "<TABLE_1>",
      ["rowId"] = "u1",
      ["data"] = new Dictionary<string, object> { ["name"] = "Walter" }
    },
    new Dictionary<string, object>
    {
      ["action"] = "increment",
      ["databaseId"] = "<DB_B>",
      ["tableId"] = "<TABLE_2>",
      ["rowId"] = "u2",
      ["data"] = new Dictionary<string, object> { ["value"] = 1, ["min"] = 0, ["column"] = "credits" }
    }
  }
);
```
```server-dart
await tablesDB.createOperations(
  transactionId: tx.Id,
  operations: [
    {
      'action': 'create',
      'databaseId': '<DB_A>',
      'tableId': '<TABLE_1>',
      'rowId': 'u1',
      'data': { 'name': 'Walter' }
    },
    {
      'action': 'increment',
      'databaseId': '<DB_B>',
      'tableId': '<TABLE_2>',
      'rowId': 'u2',
      'data': { 'value': 1, 'min': 0, 'column': 'credits' }
    }
  ]
);
```
```server-swift
try await tablesDB.createOperations(
  transactionId: tx.$id,
  operations: [
    [
      "action": "create",
      "databaseId": "<DB_A>",
      "tableId": "<TABLE_1>",
      "rowId": "u1",
      "data": ["name": "Walter"]
    ],
    [
      "action": "increment",
      "databaseId": "<DB_B>",
      "tableId": "<TABLE_2>",
      "rowId": "u2",
      "data": ["value": 1, "min": 0, "column": "credits"]
    ]
  ]
)
```
```server-rust
use appwrite::Client;
use appwrite::services::tables_db::TablesDB;
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 tables_db = TablesDB::new(&client);

    let tx = tables_db.create_transaction(None).await?;

    // Stage multiple operations at once
    tables_db.create_operations(
        &tx.id,
        Some(vec![
            json!({
                "action": "create",
                "databaseId": "<DB_A>",
                "tableId": "<TABLE_1>",
                "rowId": "u1",
                "data": { "name": "Walter" }
            }),
            json!({
                "action": "increment",
                "databaseId": "<DB_B>",
                "tableId": "<TABLE_2>",
                "rowId": "u2",
                "data": { "value": 1, "min": 0, "column": "credits" }
            }),
        ]),
    ).await?;

    Ok(())
}
```
{% /multicode %}

# Commit or roll back {% #commit-or-rollback %}

When you are done staging operations, call the `updateTransaction` method to finalize the transaction.

{% multicode %}
```client-web
// Commit
await tablesDB.updateTransaction({
  transactionId: tx.$id,
  commit: true
});

// Or roll back
await tablesDB.updateTransaction({
  transactionId: tx.$id,
  rollback: true
});
```
```client-flutter
// Commit
await tablesDB.updateTransaction(
  transactionId: tx.$id,
  commit: true
);

// Roll back
await tablesDB.updateTransaction(
  transactionId: tx.$id,
  rollback: true
);
```
```client-apple
// Commit
try await tablesDB.updateTransaction(
  transactionId: tx.$id,
  commit: true
)

// Roll back
try await tablesDB.updateTransaction(
  transactionId: tx.$id,
  rollback: true
)
```
```server-kotlin
// Commit
tablesDB.updateTransaction(
  transactionId = tx.$id,
  commit = true
)

// Roll back
tablesDB.updateTransaction(
  transactionId = tx.$id,
  rollback = true
)
```
```server-java
// Commit (asynchronous)
tablesDB.updateTransaction(
  "<TRANSACTION_ID>",
  true,
  false,
  new CoroutineCallback<>((result, error) -> {
    if (error != null) {
      error.printStackTrace();
      return null;
    }
    System.out.println(result);
    return null;
  })
);

// Roll back (asynchronous)
tablesDB.updateTransaction(
  "<TRANSACTION_ID>",
  false,
  true,
  new CoroutineCallback<>((result, error) -> {
    if (error != null) {
      error.printStackTrace();
      return null;
    }
    System.out.println(result);
    return null;
  })
);
```
```client-react-native
// Commit
await tablesDB.updateTransaction({
  transactionId: tx.$id,
  commit: true
});

// Roll back
await tablesDB.updateTransaction({
  transactionId: tx.$id,
  rollback: true
});
```
```server-nodejs
// Commit
await tablesDB.updateTransaction({
  transactionId: tx.$id,
  commit: true
});

// Roll back
await tablesDB.updateTransaction({
  transactionId: tx.$id,
  rollback: true
});
```
```server-python
# Commit
tablesDB.update_transaction(
  transaction_id = tx.id,
  commit = True
)

# Roll back
tablesDB.update_transaction(
  transaction_id = tx.id,
  rollback = True
)
```
```server-php
// Commit
$tablesDB->updateTransaction(
  transactionId: $tx['$id'],
  commit: true
);

// Roll back
$tablesDB->updateTransaction(
  transactionId: $tx['$id'],
  rollback: true
);
```
```server-ruby
# Commit
tablesDB.update_transaction(
  transaction_id: tx['$id'],
  commit: true
)

# Roll back
tablesDB.update_transaction(
  transaction_id: tx['$id'],
  rollback: true
)
```
```server-dotnet
// Commit
await tablesDB.UpdateTransaction(
  transactionId: tx.Id,
  commit: true
);

// Roll back
await tablesDB.UpdateTransaction(
  transactionId: tx.Id,
  rollback: true
);
```
```server-dart
// Commit
await tablesDB.updateTransaction(
  transactionId: tx.Id,
  commit: true
);

// Roll back
await tablesDB.updateTransaction(
  transactionId: tx.Id,
  rollback: true
);
```
```server-rust
use appwrite::Client;
use appwrite::services::tables_db::TablesDB;

#[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 tables_db = TablesDB::new(&client);

    // Commit
    tables_db.update_transaction(
        "<TRANSACTION_ID>",
        Some(true),
        None,
    ).await?;

    // Roll back
    tables_db.update_transaction(
        "<TRANSACTION_ID>",
        None,
        Some(true),
    ).await?;

    Ok(())
}
```
{% /multicode %}

# Handle conflicts {% #handle-conflicts %}

On commit, Appwrite verifies that rows affected by your transaction haven’t changed externally since they were staged. If a conflicting change is detected, the commit fails with a conflict error. Resolve the conflict (for example, refetch and re-stage) and try again.

{% info title="Best practices" %}
Keep transactions short-lived to reduce the likelihood of conflicts. Stage related updates in the order they must be applied. Prefer `createOperations` when you need to stage many changes across multiple tables.
{% /info %}

{% arrow_link href="/docs/references" %}
Explore the API references
{% /arrow_link %}
