Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ditto.live/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This guide covers the essential changes needed to migrate your Ditto Java app from v4 to v5. The main architectural shift is moving from identity-based initialization to a three-phase configuration model with CompletableFuture-based APIs. Also required: v5 uses DQL (Ditto Query Language) for all data operations. See the DQL Migration Guide for query migration steps.

AI Agent Prompt

Use this prompt when working with an AI coding assistant to migrate your Ditto Java app from v4 to v5.
I need help migrating a Ditto Java application from v4 to v5. Focus on these critical changes:

INITIALIZATION:
Replace new Ditto() with DittoFactory.create(config) using Builder pattern
- Create DittoConfig with databaseId and connect mode
- OnlinePlayground β†’ new DittoConfig.Connect.Server(...)
- OfflinePlayground β†’ new DittoConfig.Connect.SmallPeersOnly(null)
- Remove updateTransportConfig, disableSyncWithV3 calls
- IMPORTANT: If maintaining v4 behavior, set DQL_STRICT_MODE=true BEFORE starting sync

AUTHENTICATION:
Set setExpirationHandler callback after initialization
- Handler called when timeUntilExpiration == 0 (initial) or > 0 (refresh)
- Use DittoAuthenticationProvider.development() for playground tokens
- login() returns CompletableFuture with .thenAccept() and .exceptionally()

BEFORE (V4):
```java
Ditto ditto = new Ditto(
    new DittoIdentity.OnlinePlayground(
        context,
        "your-app-id",
        "your-token",
        false,
        "https://your-server.ditto.live"
    )
);
ditto.updateTransportConfig(config -> {
    config.connect.webSocketURLs.add("wss://...");
});
ditto.disableSyncWithV3();
ditto.startSync();
```

AFTER (V5):
```java
DittoConfig config = new DittoConfig.Builder("your-database-id")
    .connect(new DittoConfig.Connect.Server("https://your-server.ditto.live"))
    .build();

Ditto ditto = DittoFactory.create(config);

ditto.getAuth().setExpirationHandler((expiringDitto, timeUntilExpiration) -> {
    expiringDitto.getAuth().login("your-token", DittoAuthenticationProvider.development())
        .thenAccept(clientInfo -> {
            System.out.println("Authentication successful");
        })
        .exceptionally(error -> {
            System.out.println("Authentication failed: " + error);
            return null;
        });
});

// If maintaining v4 behavior, set strict mode BEFORE starting sync
// ditto.getStore().execute("ALTER SYSTEM SET DQL_STRICT_MODE = true", null);

ditto.getSync().start();
```

CHECKLIST:
- Replace new Ditto() with DittoFactory.create(config)
- Create DittoConfig with databaseId and connect
- Replace ditto.startSync() with ditto.getSync().start()
- Set DQL_STRICT_MODE=true BEFORE getSync().start() if maintaining v4 behavior
- Set setExpirationHandler for authentication
- Remove updateTransportConfig, disableSyncWithV3 calls
- Replace getPeerKeyString() with getPeerKey()

Work through the codebase systematically. Show me each file's changes.

Ditto Instance Initialization

v5 separates initialization into three distinct phases for better clarity and control:
// 1. Configure
DittoConfig config = new DittoConfig.Builder("your-database-id")
    .connect(new DittoConfig.Connect.Server("https://your-server.ditto.live"))
    .build();

// 2. Initialize
Ditto ditto = DittoFactory.create(config);

// 3. Authenticate
ditto.getAuth().setExpirationHandler((expiringDitto, timeUntilExpiration) -> {
    expiringDitto.getAuth().login("your-token", DittoAuthenticationProvider.development())
        .thenAccept(clientInfo -> {
            System.out.println("Authentication successful");
        })
        .exceptionally(error -> {
            System.out.println("Authentication failed: " + error);
            return null;
        });
});

// 4. Start sync
ditto.getSync().start();
These changes provide:
  • Clear separation of connection, initialization, and authentication concerns
  • CompletableFuture-based async authentication
  • No workarounds needed (transport config, DQL strict mode, v3 sync disable)
  • Type-safe configuration with compile-time validation
Initialization Migration Steps
1

Replace Initialization

Replace new Ditto() constructor with DittoFactory.create(config).
DittoConfig config = new DittoConfig.Builder("your-database-id")
    .connect(new DittoConfig.Connect.Server("https://your-server.ditto.live"))
    .build();

Ditto ditto = DittoFactory.create(config);
// Set up auth handler before starting sync (see Step 2)
ditto.getSync().start();
Key changes:
  • Use DittoConfig.Builder pattern instead of DittoIdentity
  • appId β†’ databaseId
  • .OnlinePlayground β†’ new DittoConfig.Connect.Server(...)
  • .OfflinePlayground β†’ new DittoConfig.Connect.SmallPeersOnly(null)
  • Remove updateTransportConfig, disableSyncWithV3(), and DQL strict mode queries
2

Update Authentication

Set authentication handler separately after initialization.
// Set handler after DittoFactory.create()
ditto.getAuth().setExpirationHandler((expiringDitto, timeUntilExpiration) -> {
    if (timeUntilExpiration == 0) {
        // Initial auth
        expiringDitto.getAuth().login(
            "your-token",
            DittoAuthenticationProvider.development()
        ).thenAccept(clientInfo -> {
            System.out.println("Authentication successful");
        }).exceptionally(error -> {
            System.out.println("Authentication failed: " + error);
            return null;
        });
    } else {
        // Token refresh
        refreshToken(expiringDitto);
    }
});
Key changes:
  • Authentication now uses setExpirationHandler callback
  • Handler called when auth required (timeUntilExpiration == 0) or token expiring
  • Use DittoAuthenticationProvider.development() for playground tokens
  • Custom auth: new DittoAuthenticationProvider("your-provider")

Additional Changes

DQL Strict Mode Behavior Change

Breaking Change: v5 defaults to DQL_STRICT_MODE=false, which fundamentally changes how DQL queries behave.
  • v4 default: Objects treated as REGISTER (whole-object replacement)
  • v5 default: Objects treated as MAP (field-level merging)
This affects the behavior of all DQL SELECT, INSERT, and UPDATE operations.
Choose the appropriate migration path based on your current v4 configuration:
If you’re currently using the v4 default (DQL_STRICT_MODE=true), you must explicitly set strict mode to true in v5 before starting sync or executing any queries.
Failing to set strict mode will cause objects to merge at the field level instead of replacing entirely, which can result in unexpected data behavior and perceived data loss.
To migrate to DQL_STRICT_MODE=false (the new v5 default), contact Ditto Customer Support for guidance.
DittoConfig config = new DittoConfig.Builder("your-database-id")
    .connect(new DittoConfig.Connect.Server("https://your-server.ditto.live"))
    .build();
Ditto ditto = DittoFactory.create(config);

// IMPORTANT: Set strict mode BEFORE starting sync or running queries
ditto.getStore().execute("ALTER SYSTEM SET DQL_STRICT_MODE = true", null);

// Now safe to start sync
ditto.getSync().start();
If you explicitly set DQL_STRICT_MODE=false in v4, no changes are required.v5 uses DQL_STRICT_MODE=false as the default, so your existing DQL queries will behave identically. You can upgrade freely.Optional: You can remove the explicit ALTER SYSTEM SET DQL_STRICT_MODE = false statement in v5 since this is now the default behavior.
DittoConfig config = new DittoConfig.Builder("your-database-id")
    .connect(new DittoConfig.Connect.Server("https://your-server.ditto.live"))
    .build();
Ditto ditto = DittoFactory.create(config);

// No need to set DQL_STRICT_MODE - false is now the default
ditto.getSync().start();
The Legacy Query Builder has been removed in v5. All queries must be converted to DQL before upgrading.Good news: Legacy Query Builder functionality has 1:1 support with DQL_STRICT_MODE=false (the v5 default), making migrations straightforward.Migration Steps:
  1. In v4: Set DQL_STRICT_MODE=false after initialization:
    Ditto ditto = new Ditto(
        new DittoIdentity.OnlinePlayground(
            context,
            "your-app-id",
            "your-token",
            false,
            "https://your-server.ditto.live"
        )
    );
    
    // Set DQL_STRICT_MODE to false for Query Builder compatibility
    ditto.getStore().execute("ALTER SYSTEM SET DQL_STRICT_MODE = false", null);
    
    ditto.startSync();
    
  2. Convert all queries from Legacy Query Builder to DQL See the Java Legacy→DQL Migration Guide for detailed conversion examples.
  3. Upgrade to v5 No DQL configuration changes requiredβ€”v5 defaults to DQL_STRICT_MODE=false.

Default Persistence Directory

v5 includes the database ID in the default directory name: ditto-{databaseId} instead of ditto To maintain v4 compatibility:
DittoConfig config = new DittoConfig.Builder("your-database-id")
    .connect(new DittoConfig.Connect.Server("https://your-server.ditto.live"))
    .persistenceDirectory("/app/data/ditto")  // Old v4 path
    .build();

API Changes

  • ditto.startSync() β†’ ditto.getSync().start()
  • ditto.stopSync() β†’ ditto.getSync().stop()
  • ditto.isSyncActive() β†’ ditto.getSync().isActive()
  • getPeerKeyString() β†’ getPeerKey()
  • isConnectedToDittoCloud() β†’ isConnectedToDittoServer()
  • new Ditto() β†’ DittoFactory.create(config)

Migration Checklist

Initialization

  • Replace new Ditto() with DittoFactory.create(config)
  • Create DittoConfig with databaseId and connect mode
  • Update .OnlinePlayground β†’ new DittoConfig.Connect.Server(...)
  • Update .OfflinePlayground β†’ new DittoConfig.Connect.SmallPeersOnly(null)
  • Remove updateTransportConfig calls
  • Remove disableSyncWithV3() calls
  • Set DQL_STRICT_MODE=true BEFORE starting sync if maintaining v4 behavior

Authentication

  • Set setExpirationHandler callback after initialization
  • Use DittoAuthenticationProvider.development() for playground tokens
  • Remove authentication from identity configuration

Sync API

  • Update ditto.startSync() β†’ ditto.getSync().start()
  • Update ditto.stopSync() β†’ ditto.getSync().stop()
  • Remove disableSyncWithV3() calls

Breaking Changes

  • Set persistenceDirectory if maintaining v4 directory structure
  • Update getPeerKeyString() β†’ getPeerKey()
  • Update isConnectedToDittoCloud() β†’ isConnectedToDittoServer()

Verification

  • Build compiles with zero errors
  • No deprecated API warnings
  • Observers update data immediately
  • Authentication works before sync starts
  • No memory leaks