Skip to main content
This feature is available in SDK version 4.12.0 and later.
Every data modification in Ditto returns a commit ID that you can use to track when that specific commit reaches other peers in your mesh network.

What Are Commit IDs?

Commit IDs are unique, monotonically increasing identifiers assigned to each data modification on your device:
let result = try await ditto.store.execute(
  query: "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
)
print("Commit ID: \(result.commitID ?? -1)") // e.g., 1547
ditto.store.execute(
    "UPDATE products SET price = 99.99 WHERE _id = 'product-123'",
) { result ->
    println("Commit ID: ${result.commitId}") // e.g., 1547
}
const result = await ditto.store.execute(
  "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
console.log('Commit ID:', result.commitID); // e.g., 1547
import { Ditto, QueryResult } from '@dittolive/ditto'

const result: QueryResult = await ditto.store.execute(
  "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
)
const commitID: number | undefined = result.commitID
console.log('Commit ID:', commitID) // e.g., 1547
final result = await ditto.store.execute(
  "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
print("Commit ID: ${result.commitID}"); // e.g., 1547
try (DittoQueryResult result = ditto.store.execute(
  "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
)) {
  System.out.println("Commit ID: " + result.getCommitId()); // e.g., 1547
}
using var result = await ditto.Store.ExecuteAsync(
  "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
Console.WriteLine($"Commit ID: {result.CommitID}"); // e.g., 1547
auto result = store.execute(
  "UPDATE products SET price = 99.99 WHERE _id = 'product-123'"
);
std::cout << "Commit ID: " << result.commitID() << std::endl; // e.g., 1547
let result = ditto.store().execute((
  "UPDATE products SET price = 99.99 WHERE _id = 'product-123'",
  serde_json::Value::Null
)).await?;
println!("Commit ID: {:?}", result.commit_id()); // e.g., Some(1547)
result, err := dit.Store().Execute(
    "UPDATE products SET price = 99.99 WHERE _id = 'product-123'")
if err != nil {
    return err
}
defer result.Close()  // cleanup
if commitID, ok := result.CommitID(); ok {
    fmt.Printf("Commit ID: %s\n", commitID)  // e.g. 1547
}

Key Properties

  • Monotonic - Always increasing (1547, 1548, 1549…)
  • Device-specific - Each device has its own sequence
  • Per-operation - Every INSERT, UPDATE, DELETE gets a new ID
  • Trackable - Use with system:data_sync_info to monitor sync progress

Tracking Sync Progress

Compare your commit ID with synced_up_to_local_commit_id to see if peers have received your commit:
// Step 1: Execute statement and get commit ID
let result = try await ditto.store.execute(
  query: "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  arguments: ["id": "order-456"]
)
let commitId = result.commitID!

// Step 2: Check if it synced to cloud
let syncResult = try await ditto.store.execute(
  query: "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
)

if let item = syncResult.items.first,
   let documents = item.value["documents"] as? [String: Any],
   let syncedUpTo = documents["synced_up_to_local_commit_id"] as? Int64 {

  if syncedUpTo >= commitId {
    print("Commit synced to cloud")
  } else {
    print("Syncing...")
  }
}
// Step 1: Execute the write and capture its commit ID.
val commitId: ULong = ditto.store.execute(
    query = "UPDATE orders SET status = 'shipped' WHERE _id = :id",
    arguments = mapOf("id" to "order-456"),
) { result -> result.commitId!! }

// Step 2: Check if it synced to cloud.
ditto.store.execute(
    "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
) { syncResult ->
    val item = syncResult.items.firstOrNull()
    val syncedUpTo = item?.value?.get("documents")?.dictionaryOrNull
        ?.let { it["synced_up_to_local_commit_id"].uLongOrNull }
        ?: 0u.toULong()

    if (syncedUpTo >= commitId) {
        println("Commit synced to cloud")
    } else {
        println("Syncing…")
    }
}
// Step 1: Execute statement and get commit ID
const result = await ditto.store.execute(
  "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  { id: "order-456" }
);
const commitId = result.commitID;

// Step 2: Check if it synced to cloud
const syncResult = await ditto.store.execute(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);

if (syncResult.items.length > 0) {
  const syncedUpTo = syncResult.items[0].value.documents.synced_up_to_local_commit_id;

  if (syncedUpTo >= commitId) {
    console.log("Commit synced to cloud");
  } else {
    console.log("Syncing...");
  }
}
import { Ditto, QueryResult } from '@dittolive/ditto'

interface SyncDocuments {
  sync_session_status: string
  synced_up_to_local_commit_id: number
  last_update_received_time: number
}

interface PeerSyncInfo {
  _id: string
  is_ditto_server: boolean
  documents: SyncDocuments
}

// Step 1: Execute statement and get commit ID
const result: QueryResult = await ditto.store.execute(
  "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  { id: "order-456" }
)
const commitId: number = result.commitID!

// Step 2: Check if it synced to cloud
const syncResult: QueryResult = await ditto.store.execute(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
)

if (syncResult.items.length > 0) {
  const peer = syncResult.items[0].value as PeerSyncInfo
  const syncedUpTo: number = peer.documents.synced_up_to_local_commit_id

  if (syncedUpTo >= commitId) {
    console.log("Commit synced to cloud")
  } else {
    console.log("Syncing...")
  }
}
// Step 1: Execute statement and get commit ID
final result = await ditto.store.execute(
  "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  {"id": "order-456"}
);
final commitId = result.commitID!;

// Step 2: Check if it synced to cloud
final syncResult = await ditto.store.execute(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);

if (syncResult.items.isNotEmpty) {
  final documents = syncResult.items[0].value["documents"] as Map<String, dynamic>;
  final syncedUpTo = documents["synced_up_to_local_commit_id"] as int;

  if (syncedUpTo >= commitId) {
    print("Commit synced to cloud");
  } else {
    print("Syncing...");
  }
}
// Step 1: Execute statement and get commit ID
try (DittoQueryResult result = ditto.store.execute(
  "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  Collections.singletonMap("id", "order-456")
)) {
  long commitId = result.getCommitId();

  // Step 2: Check if it synced to cloud
  try (DittoQueryResult syncResult = ditto.store.execute(
    "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
  )) {
    if (!syncResult.getItems().isEmpty()) {
      Map<String, Object> value = syncResult.getItems().get(0).getValue();
      Map<String, Object> documents = (Map<String, Object>) value.get("documents");
      long syncedUpTo = (Long) documents.get("synced_up_to_local_commit_id");

      if (syncedUpTo >= commitId) {
        System.out.println("Commit synced to cloud");
      } else {
        System.out.println("Syncing...");
      }
    }
  }
}
// Step 1: Execute statement and get commit ID
using var result = await ditto.Store.ExecuteAsync(
  "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  new Dictionary<string, object> { { "id", "order-456" } }
);
var commitId = result.CommitID;

// Step 2: Check if it synced to cloud
using var syncResult = await ditto.Store.ExecuteAsync(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);

if (syncResult.Items.Count > 0) {
  var value = (Dictionary<string, object>)syncResult.Items[0].Value;
  var documents = (Dictionary<string, object>)value["documents"];
  var syncedUpTo = (long)documents["synced_up_to_local_commit_id"];

  if (syncedUpTo >= commitId) {
    Console.WriteLine("Commit synced to cloud");
  } else {
    Console.WriteLine("Syncing...");
  }
}
// Step 1: Execute statement and get commit ID
auto result = store.execute(
  "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  {{"id", "order-456"}}
);
auto commitId = result.commitID();

// Step 2: Check if it synced to cloud
auto syncResult = store.execute(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
);

if (!syncResult.items().empty()) {
  const auto& value = syncResult.items()[0].value();
  const auto& documents = value.at("documents").get<std::map<std::string, std::any>>();
  auto syncedUpTo = std::any_cast<int64_t>(documents.at("synced_up_to_local_commit_id"));

  if (syncedUpTo >= commitId) {
    std::cout << "Commit synced to cloud" << std::endl;
  } else {
    std::cout << "Syncing..." << std::endl;
  }
}
// Step 1: Execute statement and get commit ID
let result = ditto.store().execute((
  "UPDATE orders SET status = 'shipped' WHERE _id = :id",
  serde_json::json!({"id": "order-456"})
)).await?;
let commit_id = result.commit_id().unwrap();

// Step 2: Check if it synced to cloud
let sync_result = ditto.store().execute((
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  serde_json::Value::Null
)).await?;

if let Some(item) = sync_result.get_item(0) {
  if let Some(value) = item.value().as_object() {
    if let Some(documents) = value.get("documents").and_then(|d| d.as_object()) {
      if let Some(synced_up_to) = documents.get("synced_up_to_local_commit_id").and_then(|s| s.as_i64()) {
        if synced_up_to >= commit_id as i64 {
          println!("Commit synced to cloud");
        } else {
          println!("Syncing...");
        }
      }
    }
  }
}
// Step 1: Execute statement and get commit ID
result, err := dit.Store().Execute(
    "UPDATE orders SET status = 'shipped' WHERE _id = :id",
    ditto.QueryArguments{"id" : "order-456"})
if err != nil {
    return err
}
defer result.Close()  // cleanup
commitID, _ := result.CommitID()

// Step 2: Check if it synced to cloud
syncResult, err := dit.Store().Execute(
    "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true")
if err != nil {
    return err
}

if result.ItemCount() > 0 {
    item := result.Item(0)
    defer item.Close()  // cleanup
    if documents, ok := item.Value()["documents"].(map[string]any); ok; {
        if syncedUpTo, ok := documents["synced_up_to_local_commit_id].(int64); ok {
            if syncedUpTo > commitID {
                fmt.Println("Commit synced to cloud")
            } else {
                fmt.Println("Syncing...)
            }
        }
    }
}

Monitoring Multiple Commits

Observers on system:data_sync_info result in the callback triggering every 500ms even when the result remains the same. This frequency can be configured using the live_query_system_collection_refresh_interval system parameter.
Track several commits and watch them sync in order:
var pendingCommits: [Int64] = []

// Make several commits
let result1 = try await ditto.store.execute(
  query: "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
)
if let commitId1 = result1.commitID {
  pendingCommits.append(commitId1)
}

let result2 = try await ditto.store.execute(
  query: "INSERT INTO orders DOCUMENTS (:order)",
  arguments: ["order": ["_id": "order-789", "status": "pending"]]
)
if let commitId2 = result2.commitID {
  pendingCommits.append(commitId2)
}

// Watch them sync
let observer = ditto.store.registerObserver(
  query: "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true"
) { result in
  guard let item = result.items.first,
        let documents = item.value["documents"] as? [String: Any],
        let syncedUpTo = documents["synced_up_to_local_commit_id"] as? Int64 else { return }

  // Check which commits have synced
  var syncedCount = 0
  for commitId in pendingCommits {
    if syncedUpTo >= commitId {
      print("Commit \(commitId) synced")
      syncedCount += 1
    } else {
      break
    }
  }

  // Remove synced commits
  if syncedCount > 0 {
    pendingCommits.removeFirst(syncedCount)
    print("\(pendingCommits.count) commits remaining")
  }
}
val pendingCommits = mutableListOf<ULong>()

// Make several commits β€” pass a handler to capture each commit ID.
ditto.store.execute(
    "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'",
) { result -> result.commitId?.let { pendingCommits.add(it) } }

ditto.store.execute(
    query = "INSERT INTO orders DOCUMENTS (:order)",
    arguments = mapOf("order" to mapOf("_id" to "order-789", "status" to "pending")),
) { result -> result.commitId?.let { pendingCommits.add(it) } }

// Watch them sync. The handler is suspend; the result is auto-closed when it
// returns. Read nested fields with typed accessors β€” not Kotlin casts.
ditto.store.registerObserver(
    "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
) { result ->
    val item = result.items.firstOrNull() ?: return@registerObserver
    val syncedUpTo = item.value["documents"].dictionaryOrNull
        ?.let { it["synced_up_to_local_commit_id"].uLongOrNull }
        ?: return@registerObserver

    // Check which commits have synced
    var syncedCount = 0
    for (commitId in pendingCommits) {
        if (syncedUpTo >= commitId) {
            println("βœ… Commit $commitId synced")
            syncedCount++
        } else {
            break
        }
    }

    if (syncedCount > 0) {
        repeat(syncedCount) { pendingCommits.removeAt(0) }
        println("${pendingCommits.size} commits remaining")
    }
}
const pendingCommits = [];

// Make several commits
const result1 = await ditto.store.execute(
  "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
pendingCommits.push(result1.commitID);

const result2 = await ditto.store.execute(
  "INSERT INTO orders DOCUMENTS (:order)",
  { order: { _id: "order-789", status: "pending" } }
);
pendingCommits.push(result2.commitID);

// Watch them sync
const observer = ditto.store.registerObserver(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  (result) => {
    if (!result.items.length) return;

    const syncedUpTo = result.items[0].value.documents.synced_up_to_local_commit_id;

    // Check which commits have synced
    let syncedCount = 0;
    for (const commitId of pendingCommits) {
      if (syncedUpTo >= commitId) {
        console.log(`Commit ${commitId} synced`);
        syncedCount++;
      } else {
        break;
      }
    }

    // Remove synced commits
    if (syncedCount > 0) {
      pendingCommits.splice(0, syncedCount);
      console.log(`${pendingCommits.length} commits remaining`);
    }
  }
);
import { Ditto, QueryResult, StoreObserver } from '@dittolive/ditto'

interface SyncDocuments {
  sync_session_status: string
  synced_up_to_local_commit_id: number
  last_update_received_time: number
}

interface PeerSyncInfo {
  _id: string
  is_ditto_server: boolean
  documents: SyncDocuments
}

const pendingCommits: number[] = []

// Make several commits
const result1: QueryResult = await ditto.store.execute(
  "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
)
if (result1.commitID !== undefined) {
  pendingCommits.push(result1.commitID)
}

const result2: QueryResult = await ditto.store.execute(
  "INSERT INTO orders DOCUMENTS (:order)",
  { order: { _id: "order-789", status: "pending" } }
)
if (result2.commitID !== undefined) {
  pendingCommits.push(result2.commitID)
}

// Watch them sync
const observer: StoreObserver = ditto.store.registerObserver(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  (result: QueryResult) => {
    if (!result.items.length) return

    const peer = result.items[0].value as PeerSyncInfo
    const syncedUpTo: number = peer.documents.synced_up_to_local_commit_id

    // Check which commits have synced
    let syncedCount: number = 0
    for (const commitId of pendingCommits) {
      if (syncedUpTo >= commitId) {
        console.log(`Commit ${commitId} synced`)
        syncedCount++
      } else {
        break
      }
    }

    // Remove synced commits
    if (syncedCount > 0) {
      pendingCommits.splice(0, syncedCount)
      console.log(`${pendingCommits.length} commits remaining`)
    }
  }
)
final pendingCommits = <int>[];

// Make several commits
final result1 = await ditto.store.execute(
  "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
if (result1.commitID != null) {
  pendingCommits.add(result1.commitID!);
}

final result2 = await ditto.store.execute(
  "INSERT INTO orders DOCUMENTS (:order)",
  {"order": {"_id": "order-789", "status": "pending"}}
);
if (result2.commitID != null) {
  pendingCommits.add(result2.commitID!);
}

// Watch them sync
final observer = ditto.store.registerObserver(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  (result) {
    if (result.items.isEmpty) return;

    final documents = result.items[0].value["documents"] as Map<String, dynamic>;
    final syncedUpTo = documents["synced_up_to_local_commit_id"] as int;

    // Check which commits have synced
    int syncedCount = 0;
    for (final commitId in pendingCommits) {
      if (syncedUpTo >= commitId) {
        print("Commit $commitId synced");
        syncedCount++;
      } else {
        break;
      }
    }

    // Remove synced commits
    if (syncedCount > 0) {
      pendingCommits.removeRange(0, syncedCount);
      print("${pendingCommits.length} commits remaining");
    }
  }
);
List<BigInteger> pendingCommits = new ArrayList<>();

// Make several commits
try (DittoQueryResult result1 = ditto.store.execute(
  "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
)){
    if (result1.getCommitId() != null) {
        pendingCommits.add(result1.getCommitId());
    }
}

try (DittoQueryResult result2 = ditto.store.execute(
  "INSERT INTO orders DOCUMENTS (:order)",
  Collections.singletonMap("order", Map.of("_id", "order-789", "status", "pending"))
)){
    if (result2.getCommitId() != null) {
        pendingCommits.add(result2.getCommitId());
    }
}

// Watch them sync
ditto.store.registerObserver(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  (result) -> {
      try (result)
      {
        if (result.getItems().isEmpty()) return;

        Map<String, Object> value = result.getItems().get(0).getValue();
        Map<String, Object> documents = (Map<String, Object>) value.get("documents");
        long syncedUpTo = (Long) documents.get("synced_up_to_local_commit_id");

        // Check which commits have synced
        int syncedCount = 0;
        for (BigInteger commitId : pendingCommits) {
          if (syncedUpTo >= commitId.longValue()) {
              System.out.println("Commit " + commitId + " synced");
              syncedCount++;
          } else {
              break;
          }
        }

        // Remove synced commits
        if (syncedCount > 0) {
          pendingCommits.subList(0, syncedCount).clear();
          System.out.println(pendingCommits.size() + " commits remaining");
        }
      }
  }
);
var pendingCommits = new List<long>();

// Make several commits
using var result1 = await ditto.Store.ExecuteAsync(
  "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
if (result1.CommitID.HasValue) {
  pendingCommits.Add(result1.CommitID.Value);
}

using var result2 = await ditto.Store.ExecuteAsync(
  "INSERT INTO orders DOCUMENTS (:order)",
  new Dictionary<string, object> {
    { "order", new Dictionary<string, object> {
      { "_id", "order-789" },
      { "status", "pending" }
    }}
  }
);
if (result2.CommitID.HasValue) {
  pendingCommits.Add(result2.CommitID.Value);
}

// Watch them sync
var observer = ditto.Store.RegisterObserver(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  (result) => {
    using (result)
    {
      if (result.Items.Count == 0) return;

      var value = (Dictionary<string, object>)result.Items[0].Value;
      var documents = (Dictionary<string, object>)value["documents"];
      var syncedUpTo = (long)documents["synced_up_to_local_commit_id"];

      // Check which commits have synced
      int syncedCount = 0;
      foreach (var commitId in pendingCommits) {
        if (syncedUpTo >= commitId) {
          Console.WriteLine($"Commit {commitId} synced");
          syncedCount++;
        } else {
          break;
        }
      }

      // Remove synced commits
      if (syncedCount > 0) {
        pendingCommits.RemoveRange(0, syncedCount);
        Console.WriteLine($"{pendingCommits.Count} commits remaining");
      }
    }
  }
);
std::vector<int64_t> pendingCommits;

// Make several commits
auto result1 = store.execute(
  "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"
);
if (result1.commitID().has_value()) {
  pendingCommits.push_back(result1.commitID().value());
}

auto result2 = store.execute(
  "INSERT INTO orders DOCUMENTS (:order)",
  {{"order", std::map<std::string, std::any>{
    {"_id", std::string("order-789")},
    {"status", std::string("pending")}
  }}}
);
if (result2.commitID().has_value()) {
  pendingCommits.push_back(result2.commitID().value());
}

// Watch them sync
auto observer = store.register_observer(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  [&pendingCommits](const auto& result) {
    if (result.items().empty()) return;

    const auto& value = result.items()[0].value();
    const auto& documents = value.at("documents").get<std::map<std::string, std::any>>();
    auto syncedUpTo = std::any_cast<int64_t>(documents.at("synced_up_to_local_commit_id"));

    // Check which commits have synced
    size_t syncedCount = 0;
    for (const auto& commitId : pendingCommits) {
      if (syncedUpTo >= commitId) {
        std::cout << "Commit " << commitId << " synced" << std::endl;
        syncedCount++;
      } else {
        break;
      }
    }

    // Remove synced commits
    if (syncedCount > 0) {
      pendingCommits.erase(pendingCommits.begin(), pendingCommits.begin() + syncedCount);
      std::cout << pendingCommits.size() << " commits remaining" << std::endl;
    }
  }
);
let mut pending_commits: Vec<u64> = Vec::new();

// Make several commits
let result1 = ditto.store().execute((
  "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'",
  serde_json::Value::Null
)).await?;
if let Some(commit_id) = result1.commit_id() {
  pending_commits.push(commit_id);
}

let result2 = ditto.store().execute((
  "INSERT INTO orders DOCUMENTS (:order)",
  serde_json::json!({"order": {"_id": "order-789", "status": "pending"}})
)).await?;
if let Some(commit_id) = result2.commit_id() {
  pending_commits.push(commit_id);
}

// Watch them sync
let observer = ditto.store().register_observer(
  "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
  move |result| {
    if result.item_count() == 0 { return; }

    if let Some(item) = result.get_item(0) {
      if let Some(value) = item.value().as_object() {
        if let Some(documents) = value.get("documents").and_then(|d| d.as_object()) {
          if let Some(synced_up_to) = documents.get("synced_up_to_local_commit_id").and_then(|s| s.as_u64()) {

            // Check which commits have synced
            let mut synced_count = 0;
            for &commit_id in &pending_commits {
              if synced_up_to >= commit_id {
                println!("Commit {} synced", commit_id);
                synced_count += 1;
              } else {
                break;
              }
            }

            // Remove synced commits
            if synced_count > 0 {
              pending_commits.drain(0..synced_count);
              println!("{} commits remaining", pending_commits.len());
            }
          }
        }
      }
    }
  }
)?;
var pendingCommits []uint64

// Make several Commits
result1, err := dit.Store().Execute(
    "UPDATE inventory SET quantity = quantity - 1 WHERE _id = 'item-1'"))
if err != nil {
    return err
}
defer result1.Close()  // cleanup
if commitID, ok := result1.CommitID(); ok {
    pendingCommits = append(pendingCommits, commitID)
}

// Make several Commits
result2, err := dit.Store().Execute(
    "INSERT INTO orders DOCUMENTS (:order)",
    ditto.QueryArguments{"order" : ditto.Document{"_id" : "order-789", "status" : "pending}})
if err != nil {
    return err
}
defer result2.Close()  // cleanup
if commitID, ok := result2.CommitID(); ok {
    pendingCommits = append(pendingCommits, commitID)
}

// Watch them sync
observer, err := dit.Store().RegisterObserver(
    "SELECT * FROM system:data_sync_info WHERE is_ditto_server = true",
    nil, // no query arguments
    func(result *ditto.QueryResult) {
        defer result.Close()  // cleanup

        if result.ItemCount() == 0 {
            return
        }

        item := result.Item(0)
        defer item.Close()  // cleanup
        if documents, ok := item.Value()["documents"].(map[string]any); ok {
            if syncedUpTo, ok := documents["synced_up_to_local_commit_id"].(uint64); ok {
                // Check which commits have synced
                var syncedCount int
                for _, commitID := range pendingCommits {
                    if syncedUpTo > commitID {
                        fmt.Printf("Commit %u synced\n", commitID)
                        syncedCount++
                    } else {
                        break
                    }
                }

                // Remove synced commits
                if syncedCount > 0 {
                    pendingCommits = pendingCommits[syncedCount:]
                    fmt.Printf("%d commits remaining\n", len(pendingCommits))
                }
            }
        }
    }
)
if err != nil {
    return err
}

Transaction Behavior

Commit IDs are only assigned after transactions complete:
var queryResult: DittoQueryResult?

try await ditto.store.transaction { transaction in
  queryResult = try await transaction.execute(
    query: "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
  )

  print(queryResult?.commitID ?? "nil") // nil - not committed yet

  return try await transaction.commit()
}

print(queryResult?.commitID ?? "nil") // 1548 - now has commit ID
// Use transaction.executeRaw() to get the result inside the block, and have
// the block return the value (or just the commit ID). The transaction commits
// when you return Result.Commit. The commit ID is only assigned once the
// transaction commits.
val commitId: ULong? = (ditto.store.transaction { transaction ->
    transaction.execute(
        query = "INSERT INTO orders DOCUMENTS (:doc)",
        arguments = mapOf("doc" to mapOf("_id" to "order-123", "total" to 99.99))
    ) { txnResult ->
        // Before commit, no commit ID has been assigned yet.
        println(txnResult.commitId ?: "null") // null
        DittoTransaction.Result.Commit(txnResult.commitId)
    }
} as? DittoTransaction.Result.Commit)?.value

println(commitId ?: "null") // e.g. 1548 β€” assigned now that the txn committed
let queryResult;

await ditto.store.transaction(async (transaction) => {
  queryResult = await transaction.execute(
    "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
  );

  console.log(queryResult.commitID); // null - not committed yet

  return transaction.commit();
});

console.log(queryResult.commitID); // 1548 - now has commit ID
import { Ditto, QueryResult } from '@dittolive/ditto'

let queryResult: QueryResult | undefined

await ditto.store.transaction(async (transaction) => {
  queryResult = await transaction.execute(
    "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
  )

  console.log(queryResult.commitID) // undefined - not committed yet

  return transaction.commit()
})

console.log(queryResult?.commitID) // 1548 - now has commit ID
late QueryResult queryResult;

await ditto.store.transaction((transaction) async {
  queryResult = await transaction.execute(
    "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
  );

  print(queryResult.commitID); // null - not committed yet

  return TransactionCompletionAction.commit;
});

print(queryResult.commitID); // 1548 - now has commit ID
DittoQueryResult queryResult = null;

ditto.store.transaction((transaction) -> {
  queryResult = transaction.execute(
    "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
  );

  System.out.println(queryResult.getCommitId() != null ? queryResult.getCommitId() : "null"); // null - not committed yet

  return transaction.commit();
});

queryResult.close();
System.out.println(queryResult.getCommitId() != null ? queryResult.getCommitId() : "null"); // 1548 - now has commit ID
DittoQueryResult queryResult = null;

await ditto.Store.TransactionAsync(async (transaction) => {
  queryResult = await transaction.ExecuteAsync(
    "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
  );

  Console.WriteLine(queryResult.CommitID?.ToString() ?? "null"); // null - not committed yet

  return await transaction.CommitAsync();
});

Console.WriteLine(queryResult.CommitID?.ToString() ?? "null"); // 1548 - now has commit ID
queryResult.Dispose();
std::optional<DittoQueryResult> queryResult;

ditto.get_store().transaction([&](auto& transaction) {
  queryResult = transaction.execute(
    "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })"
  );

  std::cout << (queryResult->commitID().has_value() ?
    std::to_string(queryResult->commitID().value()) : "null") << std::endl; // null - not committed yet

  return transaction.commit();
});

std::cout << (queryResult->commitID().has_value() ?
  std::to_string(queryResult->commitID().value()) : "null") << std::endl; // 1548 - now has commit ID
let mut query_result: Option<DittoQueryResult> = None;

ditto.store().transaction(|transaction| async move {
  query_result = Some(transaction.execute((
    "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })",
    serde_json::Value::Null
  )).await?);

  println!("{:?}", query_result.as_ref().and_then(|r| r.commit_id())); // None - not committed yet

  transaction.commit().await
}).await?;

println!("{:?}", query_result.as_ref().and_then(|r| r.commit_id())); // Some(1548) - now has commit ID
var queryResult *ditto.queryResult

_, err := dit.Store().Transaction(
    nil, // default operations
    func(transaction *ditto.Transaction) (ditto.TransactionCompletionAction, err) {
        var err error
        queryResult, err = transaction.Execute(
            "INSERT INTO orders DOCUMENTS ({ _id: 'order-123', total: 99.99 })")
        if err != nil {
            return ditto.TransactionCompletionActionRollback, err
        }

        if commitID, ok := queryResult.CommitID(); ok {
            // This branch won't be taken, as commit ID is not set yet
            fmt.Printf("%d\n", commitID)
        } else {
            fmt.Println("No commit ID")
        }

        return ditto.TransactionCallbackActionCommit, nil
    }
)
if err != nil {
    return err
}
defer queryResult.Close()  // cleanup

if commitID, ok := queryResult.CommitID(); ok {
    // Now has commit ID
    fmt.Printf("%d\n", commitID)
} else {
    // This branch won't be taken
    fmt.Println("No commit ID")
}

Checking Specific Peers

Track sync progress to any peer (not just cloud servers):
// Check sync to a specific peer device
let syncResult = try await ditto.store.execute(
  query: "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
)

if let item = syncResult.items.first,
   let documents = item.value["documents"] as? [String: Any],
   let peerSyncedUpTo = documents["synced_up_to_local_commit_id"] as? Int64 {
  print("Peer has synced up to commit \(peerSyncedUpTo)")
}
// Check sync to a specific peer device. Use typed accessors on the
// DittoCborSerializable.Dictionary fields; the handler form auto-closes the
// result.
ditto.store.execute(
    "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'",
) { syncResult ->
    val item = syncResult.items.firstOrNull() ?: return@execute
    val peerSyncedUpTo = item.value["documents"].dictionaryOrNull
        ?.let { it["synced_up_to_local_commit_id"].uLongOrNull }
    println("Peer has synced up to commit ${peerSyncedUpTo ?: "?"}")
}
// Check sync to a specific peer device
const syncResult = await ditto.store.execute(
  "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);

if (syncResult.items.length > 0) {
  const peerSyncedUpTo = syncResult.items[0].value.documents.synced_up_to_local_commit_id;
  console.log(`Peer has synced up to commit ${peerSyncedUpTo}`);
}
import { Ditto, QueryResult } from '@dittolive/ditto'

interface SyncDocuments {
  sync_session_status: string
  synced_up_to_local_commit_id: number
  last_update_received_time: number
}

interface PeerSyncInfo {
  _id: string
  is_ditto_server: boolean
  documents: SyncDocuments
}

// Check sync to a specific peer device
const syncResult: QueryResult = await ditto.store.execute(
  "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
)

if (syncResult.items.length > 0) {
  const peer = syncResult.items[0].value as PeerSyncInfo
  const peerSyncedUpTo: number = peer.documents.synced_up_to_local_commit_id
  console.log(`Peer has synced up to commit ${peerSyncedUpTo}`)
}
// Check sync to a specific peer device
final syncResult = await ditto.store.execute(
  "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);

if (syncResult.items.isNotEmpty) {
  final documents = syncResult.items[0].value["documents"] as Map<String, dynamic>;
  final peerSyncedUpTo = documents["synced_up_to_local_commit_id"] as int;
  print("Peer has synced up to commit $peerSyncedUpTo");
}
// Check sync to a specific peer device
try (DittoQueryResult syncResult = ditto.store.execute(
  "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
)) {
  if (!syncResult.getItems().isEmpty()) {
    Map<String, Object> value = syncResult.getItems().get(0).getValue();
    Map<String, Object> documents = (Map<String, Object>) value.get("documents");
    long peerSyncedUpTo = (Long) documents.get("synced_up_to_local_commit_id");
    System.out.println("Peer has synced up to commit " + peerSyncedUpTo);
  }
}
// Check sync to a specific peer device
using var syncResult = await ditto.Store.ExecuteAsync(
  "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);

if (syncResult.Items.Count > 0) {
  var value = (Dictionary<string, object>)syncResult.Items[0].Value;
  var documents = (Dictionary<string, object>)value["documents"];
  var peerSyncedUpTo = (long)documents["synced_up_to_local_commit_id"];
  Console.WriteLine($"Peer has synced up to commit {peerSyncedUpTo}");
}
// Check sync to a specific peer device
auto syncResult = store.execute(
  "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'"
);

if (!syncResult.items().empty()) {
  const auto& value = syncResult.items()[0].value();
  const auto& documents = value.at("documents").get<std::map<std::string, std::any>>();
  auto peerSyncedUpTo = std::any_cast<int64_t>(documents.at("synced_up_to_local_commit_id"));
  std::cout << "Peer has synced up to commit " << peerSyncedUpTo << std::endl;
}
// Check sync to a specific peer device
let sync_result = ditto.store().execute((
  "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'",
  serde_json::Value::Null
)).await?;

if let Some(item) = sync_result.get_item(0) {
  if let Some(value) = item.value().as_object() {
    if let Some(documents) = value.get("documents").and_then(|d| d.as_object()) {
      if let Some(peer_synced_up_to) = documents.get("synced_up_to_local_commit_id").and_then(|s| s.as_u64()) {
        println!("Peer has synced up to commit {}", peer_synced_up_to);
      }
    }
  }
}
// Check sync to a specific peer device
syncResult, err := dit.Store().Execute(
    "SELECT * FROM system:data_sync_info WHERE _id = 'peer-device-456'")
if err != nil {
    return err
}
defer syncResult.Close()  // cleanup

if syncResult.ItemCount() > 0 {
    item := syncResult.Item(0)
    defer item.Close()  // cleanup
    if documents, ok := item.Value()["documents"].(map[string]any); ok {
        if peerSyncedUpTo, ok := documents["synced_up_to_local_commit_id"].(uint64); ok {
            fmt.Printf("Peer has synced up to commit %u\n", peerSyncedUpTo)
        }
    }
}

Best Practices

Remember that Ditto is offline-first. Use commit ID tracking to enhance user experience, not to block operations.
  • Don’t block operations - Let users continue working while tracking sync in background
  • Show progress indicators - Use commit tracking to display sync status in your UI
  • Handle concurrency gracefully - Tracking should enhance the experience, not block it
  • Monitor critical data - Focus tracking on important operations like payments or submissions
  • Clean up tracking - Remove old commit IDs from your tracking lists to avoid memory issues