---
title: 'Hello, World!' Sync
slug: v4-7/get-started/hello-world-sync
docTags: 
createdAt: 2024-03-05T22:34:58.537Z
---

Once you've set up your environment, try on Ditto and perform your first peer‑to‑peer sync.&#x20;

Intended to get you oriented, this article provides a streamlined process for integrating sync functionality within your app.&#x20;

:::hint{type="info"}
If you prefer building and exploring through a task app, chat app, and so on, see [Example Projects Overview](docId\:HmL3NunwO5K313jKu_Wyz).
:::

# Integrating Sync Functionality

Before you can begin syncing data offline, set up authentication and then start the sync process:

:::::WorkflowBlock
::::WorkflowBlockItem
From the top-most scope of your app's codebase, add the following to set up authentication and start syncing offline.

:::CodeblockTabs
```swift
DittoLogger.minimumLogLevel = .debug
let ditto = Ditto(identity: .onlinePlayground(
    appID: "YOUR_APP_ID",
    token: "YOUR_PLAYGROUND_TOKEN"
))
do {
  try ditto.startSync()
} catch (let err) {
  print(err.localizedDescription)
}
```

```kotlin
try {
    val androidDependencies = DefaultAndroidDittoDependencies(context)
    val identity = DittoIdentity.OnlinePlayground(
        androidDependencies,
        appId = "YOUR_APP_ID",
        token = "YOUR_PLAYGROUND_TOKEN"
    )
    DittoLogger.minimumLogLevel = DittoLogLevel.DEBUG
    ditto = Ditto(androidDependencies, identity)
    ditto.startSync()
} catch (e: DittoError) {
    Log.e("Ditto error", e.message!!)
}
```

```javascript
import { Ditto } from "@dittolive/ditto"

const identity = {
  type: 'onlinePlayground',
  appID: 'YOUR_APP_ID',
  token: 'YOUR_PLAYGROUND_TOKEN'
}

const ditto = new Ditto(identity)
await ditto.startSync()
```

```java
DittoDependencies androidDependencies = new DefaultAndroidDittoDependencies(this.context);
DittoLogger.setMinimumLogLevel(DittoLogLevel.DEBUG);
DittoIdentity identity = new DittoIdentity.OnlinePlayground(androidDependencies, "YOUR_APP_ID", "YOUR_PLAYGROUND_TOKEN");
Ditto ditto = new Ditto(androidDependencies, identity);

try {
    ditto.startSync();
} catch(DittoError e) {
    //handle error
}
```

```csharp
try
{
    DittoLogger.SetMinimumLogLevel(DittoLogLevel.Debug);
    var ditto = new Ditto(DittoIdentity.OnlinePlayground("YOUR_APP_ID", "YOUR_PLAYGROUND_TOKEN", true), path);
    ditto.StartSync();
}
catch (DittoException ex)
{
    Console.WriteLine($"Ditto Error {ex.Message}");
}
```

```cpp
auto identity =
    Identity::OnlinePlayground("YOUR_APP_ID",
                               "YOUR_PLAYGROUND_TOKEN", true);
try {
  Ditto ditto = Ditto(identity, dir);
  ditto.set_minimum_log_level(LogLevel::debug);
  ditto.start_sync();
} catch (const DittoError &err) {
}
```

```rust
// App ID and Playground Token are read from ENV variables
let your_app_id = AppId::from_env("DITTO_APP_ID")?;
let your_playground_token = std::env::var("DITTO_PLAYGROUND_TOKEN")?;
let ditto = Ditto::builder()
    // Store peer data in a directory next to the executable
    .with_root(Arc::new(PersistentRoot::from_current_exe()?))
    .with_minimum_log_level(LogLevel::Debug)
    .with_identity(move |ditto_root| {
        let enable_cloud_sync = true;
        let custom_auth_url = None;
        OnlinePlayground::new(
            ditto_root,
            your_app_id,
            your_playground_token,
            enable_cloud_sync,
            custom_auth_url,
        )
    })?
    .build()?;

ditto.start_sync()?;
```

Dart(beta)

```dart
import 'package:ditto_live/ditto_live.dart';

final dataDir = await getApplicationDocumentsDirectory();
final persistenceDirectory = Directory("${dataDir.path}/ditto");
await persistenceDirectory.create(recursive: true);

final ditto = await Ditto.open(
  identity: identity,
  persistenceDirectory: persistenceDirectory,
);

await ditto.startSync();
```
:::
::::

:::WorkflowBlockItem
Replace `YOUR_APP_ID` and `YOUR_PLAYGROUND_TOKEN` with your access credentials available from the [portal](https://portal.ditto.live/?_gl=1*gbyc26*_ga*MjAxODM3ODUyMi4xNzE4NjUzNzYz*_ga_D8PMW3CCL2*MTcxODcyNjU1MS41LjEuMTcxODcyNjkzMi42MC4wLjA.). (See [Sync Credentials](docId\:yMRWJNMDrNOvdT3qbPtXK))
:::
:::::

# Inserting Documents

Insert a document in your local Ditto store by calling the Execute API method on the `store` namespace with a local `INSERT INTO` query, specifying the document to insert.

For example, inserting a new document with a single field `"color"` set to `"blue"`:

:::CodeblockTabs
```swift
await ditto.store.execute(
  query: "INSERT INTO cars DOCUMENTS (:newCar)",
  arguments: ["newCar": ["color": "blue"]]);
```

```kotlin
ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  mapOf("newCar" to mapOf("color" to "blue")))
```

```javascript
await ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  { newCar: { color: "blue" } }
);
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "INSERT INTO cars DOCUMENTS (:newCar)",
    Collections.singletonMap("newCar", Collections.singletonMap("color", "blue")),
);
```

```csharp
var args = new Dictionary<string, object>();
args.Add("newCar", new { color = "blue" });

await ditto.Store.ExecuteAsync(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  args);
```

```cpp
std::map<std::string, std::map<std::string, std::string>> args;
args["newCar"] = {{"color", "blue"}};

ditto.get_store().execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  args);
```

```rust
let query_result = ditto
    .store()
    .execute(
        "INSERT INTO cars DOCUMENTS (:newCar)",
        Some(serde_json::json!({
            "newCar": {
                "color": "blue"
            }
        }).into()),
    ).await?;
```

```dart
await ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  arguments: {"newCar": {"color": "blue"}},
);
```
:::

# Setting Up Store Observers

Establish a local listener, known as a *store observer*, for realtime monitoring and response to updates in your local Ditto store.

For example, you can set up a store observer to asynchronously display profile updates to end users when they modify their profiles.

To set up a store observer:

:::::WorkflowBlock
:::WorkflowBlockItem
Call the Register Observer API method on the `store` namespace.&#x20;
:::

::::WorkflowBlockItem
Include a local `SELECT` query specifying the document collection you want to watch and define a callback function to handle changes.

For example, watching documents from the `cars` collection in the Ditto store:

:::CodeblockTabs
```swift
observer = ditto.store.registerObserver(
  query: "SELECT * FROM cars"){ result in /* handle change */ };
```

```kotlin
observer = ditto.store.registerObserver("SELECT * FROM cars") { result ->
  /* handle change */ };
```

```javascript
ditto.store.registerObserver(
  "SELECT * FROM cars",
  (result) => {
    // handle change
});
```

```java
observer = ditto.store.registerObserver(
    "SELECT * FROM cars",
    result -> {
        // handle change
    }
);
```

```csharp
// Without Arguments
result = await ditto.Store.RegisterObserver(
  "SELECT * FROM cars",
  (result) => {
    // handle change
  });

// With Arguments
result = ditto.Store.RegisterObserver(
  "SELECT * FROM cars",
  (result) => {
    // handle change
  });

```

```cpp
observer = ditto.get_store().register_observer(
  "SELECT * FROM cars",
  [&](QueryResult result) { /* handle change */ });
```

```rust
observer = ditto
    .store()
    .register_observer(
        "SELECT * from cars",
        None,
        move |result: QueryResult| {
            // handle change
        })?;
```

Dart(beta)

```dart
final observer = await ditto.store.registerObserver("SELECT * FROM cars");

observer.changes.listen((result) {
  // handle change
});
```
:::
::::
:::::

:::hint{type="warning"}
Please note that the observer must be kept in scope (i.e. as a property in a class) for as long as you wish to have your event handler be called when there is an update to a document matching the query you provide.
:::



# Creating Subscriptions

Register a remote listener, known as a *sync subscription*, by calling the Register Subscription API method on the `sync` namespace.&#x20;

For example, creating a subscription to sync updates made to documents in the `cars` collection with `color` set to `blue`:

:::CodeblockTabs
```swift
ditto.sync.registerSubscription("SELECT * FROM cars WHERE color = 'blue'")
```

```kotlin
ditto.sync.registerSubscription("SELECT * FROM cars WHERE color = 'blue'")
```

```javascript
ditto.sync.registerSubscription("SELECT * FROM cars WHERE color = 'blue'")
```

```java
ditto.sync.registerSubscription("SELECT * FROM cars WHERE color = 'blue'")
```

```csharp
ditto.Sync.RegisterSubscription("SELECT * FROM cars WHERE color = 'blue'");
```

```cpp
auto subscription = 
  ditto.sync().register_subscription("SELECT * FROM cars WHERE color = 'blue'");
```

```rust
let subscription = ditto
    .sync()
    .register_subscription(
        "SELECT * FROM cars WHERE color = 'blue'",
        None,
    )?;
```

Dart(beta)

```dart
ditto.sync.registerSubscription("SELECT * FROM cars WHERE color = 'blue'");
```
:::

# Takeaway

In Ditto, there is a clear distinction between traditional `CREATE`, `READ`, `UPDATE`, and `DELETE` (CRUD) database operations and data sync:

- To perform CRUD, you execute local data operations against `store` namespace.&#x20;
- To perform sync, you execute remote data operations against the `sync` namespace.&#x20;

To complete your understanding, the following graphic illustrates how sync subscriptions and store observers work together in practice:

::::WorkflowBlock
:::WorkflowBlockItem
Before you can sync offline, you must integrate sync functionality in your codebase. (See [Integrating Sync Functionality](./#integrating-sync-functionality))
:::

:::WorkflowBlockItem
Once integrated, you initiate a sync subscription request from your local Ditto store to remote peers. (See [Creating Subscriptions](./#creating-subscriptions))

The associated query specifying the data you want to watch then propagates to each end-user device connected within the mesh network:

::Image[]{src="https://api.archbee.com/api/optimize/qoRkNxW5fJ81r_NqVpc8C/B6un7DS5lflzYqDal7w-L_data-flow-sync-query.png" size="88" width="1978" height="1300" position="flex-start" showCaption="false"}
:::

:::WorkflowBlockItem
When the data you've subscribed to changes on a remote peer — whether through insertions, updates, or deletions — the remote peer automatically syncs these delta changes to your local Ditto store over the mesh network:

::Image[]{src="https://api.archbee.com/api/optimize/qoRkNxW5fJ81r_NqVpc8C/NWdlCq9SOTHs-qsz1uE-x_data-flow-sync-query3.png" size="72" width="1650" height="1300" position="flex-start" showCaption="false"}
:::

:::WorkflowBlockItem
Combining store observers with your sync subscriptions ensures that you receive updates from remote stores, enabling you to quickly respond in your app. (See [Seetting Up Store Observers](./#setting-up-store-observers))

::Image[]{src="https://api.archbee.com/api/optimize/qoRkNxW5fJ81r_NqVpc8C/gLL2rTiuac9pOV7ApCyFW_data-flow-sync-observer2.png" size="90" width="2089" height="1436" position="flex-start" showCaption="false"}
:::
::::

:::hint{type="info"}
For more information, see any of the following:

- [Data Handling Essentials](docId\:dCKm8KF7TGwDXeC2m_4tq)
- [Mesh Networking 101](docId\:nUxTqiRZyK9GYE59IxzY4)
- [Install Guides](docId\:mpAdXpzADYmeCR9wUNvgB)
- [CREATE](docId\:GGSEOwATLHBgQjiui_v-h), [READ](docId\:PkYbGOz90KhrV4xOJOah8), [UPDATE](docId:8kd9FIMNxcDOqely0ZiHs), [DELETE](docId\:gVBETw19ZKcbz2Foj5yIu)&#x20;
- [Starting and Stopping Sync](docId:0UMfKR0kbp_x_tRPQMnlt)
- [Managing Sync Subscriptions](docId\:bEm-SpHHFKsPyP5ZeE36G)
- [DQL Quick Reference](docId\:DOLGigpjTQb7pHuGVvWhX)
:::

