> ## 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.

# JavaScript

> You can integrate the Ditto SDK with your web and Node.js projects developed using JavaScript and [TypeScript](https://www.typescriptlang.org/ "TypeScript") languages.

To install the JavaScript SDK:

<Steps>
  <Step>
    [Prerequisites](#prerequisites): Confirm that you meet the minimum requirements.
  </Step>

  <Step>
    [Install Dependencies](#installing-dependencies): Add the ditto package to your environment.
  </Step>

  <Step>
    [Integrate Ditto](#integrating-ditto-and-starting-sync): Import and initialize Ditto in your app.
  </Step>

  <Step>
    [Run Ditto](#running-ditto): Authenticate with Ditto Server and start syncing offline.
  </Step>
</Steps>

## Prerequisites

Following are the minimum requirements that must be met before attempting to install Ditto.

* [Node.js](https://nodejs.org/en/) active or maintenance long-term support (LTS) version
* Linux, macOS version 11+, or Windows version 10+

## Installing Dependencies

Install the `@dittolive/ditto` package into your project:

```bash bash theme={null}
npm install @dittolive/ditto
```

## Integrating Ditto and Starting Sync

Import and initialize Ditto, and then provide your access credentials for one-time authentication with Ditto Server:

1. From the top-most scope of your app, import Ditto.

2. Using async/await, initialize Ditto. In web applications, this will download
   Ditto's WebAssembly binary. See section [Web Assets](#web-assets) for
   details on using this in a production environment.

3. Provide your access credentials by replacing the placeholders in the snippet
   below with values obtained from the Ditto portal:

   1. Replace the `databaseID` placeholder value with the database ID that identifies
      your database in Ditto.

   2. Replace the `token` placeholder value with your playground token that
      Ditto Server uses to verify your digital identity before issuing your
      playground certificate.

<Note>
  Make sure to instantiate the `Ditto` instance in the top-most scope of your app. Otherwise, it may be inadvertently garbage collected and no longer accessible throughout the lifecycle of your app.
</Note>

<Info>
  For instructions on how to obtain your access credentials, see [Getting SDK Connection Details](/cloud/portal/getting-sdk-connection-details) . For an introduction to authentication in Ditto, see *Security* > [Cloud Authentication](../auth-and-authorization/cloud-authentication).
</Info>

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { init, Ditto, DittoConfig, Authenticator } from '@dittolive/ditto'

  await init()

  const databaseID = 'REPLACE_ME_WITH_YOUR_DATABASE_ID'
  const config = new DittoConfig(databaseID, {
    mode: 'server',
    url: `https://${databaseID}.cloud.ditto.live`
  })

  const ditto = await Ditto.open(config)

  await ditto.auth.setExpirationHandler(async (ditto, secondsRemaining) => {
    console.log('Token expiring in:', secondsRemaining)
    const result = await ditto.auth.login('REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN', Authenticator.DEVELOPMENT_PROVIDER)
    if (result.error) {
      console.error('Auth error:', result.error)
    }
  })

  // Disable DQL strict mode so that collection definitions are not required in DQL queries
  await ditto.store.execute("ALTER SYSTEM SET DQL_STRICT_MODE = false")

  ditto.startSync()
  ```

  ```typescript TypeScript theme={null}
  import { init, Ditto, DittoConfig, Authenticator } from '@dittolive/ditto'

  await init()

  const databaseID: string = 'REPLACE_ME_WITH_YOUR_DATABASE_ID'
  const config = new DittoConfig(databaseID, {
    mode: 'server',
    url: `https://${databaseID}.cloud.ditto.live`
  })

  const ditto: Ditto = await Ditto.open(config)

  await ditto.auth.setExpirationHandler(async (ditto: Ditto, secondsRemaining: number) => {
    console.log('Token expiring in:', secondsRemaining)
    const result = await ditto.auth.login('REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN', Authenticator.DEVELOPMENT_PROVIDER)
    if (result.error) {
      console.error('Auth error:', result.error)
    }
  })

  // Disable DQL strict mode so that collection definitions are not required in DQL queries
  await ditto.store.execute("ALTER SYSTEM SET DQL_STRICT_MODE = false")

  ditto.startSync()
  ```
</CodeGroup>

## Running Ditto

You can now run your basic snippet using Node and should not see any errors:

```Bash Bash theme={null}
node index.js
```

## Add a Sync Subscription

Add a *sync subscription* to receive updates on documents that match its query from connected peers in the mesh.

Use `registerSubscription()` in the `ditto.sync` namespace to add a sync subscription:

<CodeGroup>
  ```JS JavaScript theme={null}
  // Add a sync subscription:
  ditto.sync.registerSubscription(`
    SELECT *
    FROM tasks
    WHERE isDeleted = false`);
  ```

  ```typescript TypeScript theme={null}
  import { SyncSubscription } from '@dittolive/ditto';

  // Add a sync subscription:
  const subscription: SyncSubscription = ditto.sync.registerSubscription(`
    SELECT *
    FROM tasks
    WHERE isDeleted = false`);
  ```
</CodeGroup>

## Listening to Changes

Now that your app is ready to receive updates to documents from other peers, you might want to react to those changes as soon as they happen. For this you can use the `registerObserver()` method on `ditto.store`. The passed in callback closure is invoked by Ditto everytime it registers new changes to documents matching the query.

<CodeGroup>
  ```JS JavaScript theme={null}
  // Add a store observer:
  ditto.store.registerObserver(`
    SELECT *
    FROM tasks
    WHERE isDeleted = false`,
    (result) => {
      console.log(`Tasks have been updated: ${result.items}`)
    }
  );

  const newTask = {
    isCompleted: false,
    isDeleted: false,
    body: "Hello world!"
  };

  // Insert a new document:
  await ditto.store.execute(`
    INSERT INTO tasks
    VALUES (:newTask)`,
    { newTask });
  ```

  ```typescript TypeScript theme={null}
  import { QueryResult, StoreObserver } from '@dittolive/ditto';

  interface Task {
    isCompleted: boolean;
    isDeleted: boolean;
    body: string;
  }

  // Add a store observer:
  const observer: StoreObserver = ditto.store.registerObserver(`
    SELECT *
    FROM tasks
    WHERE isDeleted = false`,
    (result: QueryResult) => {
      console.log(`Tasks have been updated: ${result.items}`);
    }
  );

  const newTask: Task = {
    isCompleted: false,
    isDeleted: false,
    body: "Hello world!"
  };

  // Insert a new document:
  await ditto.store.execute(`
    INSERT INTO tasks
    VALUES (:newTask)`,
    { newTask });
  ```
</CodeGroup>

## Web Assets

When Ditto is used on the web, it needs to download a WebAssembly binary
containing Ditto's core logic. This happens automatically when calling `await
init()`. By default, the SDK will fetch the asset from Ditto's CDN.

Alternatively, you can host the binary on another CDN or web server and
configure Ditto to retrieve it from there. You will find the file in the NPM
package at `web/ditto.wasm`. Make it available on a web server and provide its
URL when calling `init()`:

<CodeGroup>
  ```js JavaScript theme={null}
  await init({
    webAssemblyModule: 'https://some-custom-cdn.com/assets/ditto.wasm'
  })
  ```

  ```typescript TypeScript theme={null}
  import { init, InitOptions } from '@dittolive/ditto';

  const options: InitOptions = {
    webAssemblyModule: 'https://some-custom-cdn.com/assets/ditto.wasm'
  };

  await init(options);
  ```
</CodeGroup>

Make sure to properly configure the server to return the correct MIME type
(`application/wasm`) and [CORS headers][1].

Please consider your application's loading UI while downloading the assets as it
may take a few seconds to download and initialize the WebAssembly binary.

**It is strongly recommended to serve assets using a web server or CDN that
supports compression**. This will significantly reduce the download size of
assets and thereby the loading time of your application.

[1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin

## Packaging with `yao-pkg`

When packaging Node.js applications, tree-shaking bundlers such as webpack will automatically only include native binaries for the platform you're building.

However, `yao-pkg` requires adding aditional metadata in order to reduce the size of your executable. To configure your `package.json` to include only the binaries for your target platform:

```json theme={null}
{
  "pkg": {
    "assets": [
      ".env",
      "lib/**/*",
      "node_modules/@dittolive/ditto/node/*.node"
    ],
    "targets": [
      "node22-win-x64"
    ],
    "outputPath": "lib",
    "ignore": [
      "**/*/@dittolive/ditto/react-native/**",
      "**/*/@dittolive/ditto/web/**",
      "**/*/@dittolive/ditto/node/ditto.darwin*.node",
      "**/*/@dittolive/ditto/node/ditto.linux-*.node",
      "**/node_modules/react-native/**",
      "**/node_modules/expo*/**",
      "**/node_modules/@expo/**",
      "**/node_modules/@react-native*/**",
      "**/node_modules/@babel/**"
    ]
  }
}
```

Adjust the `ignore` patterns based on your target platform:

**For Windows:**

* Ignore: `ditto.darwin*.node` and `ditto.linux-*.node`
* Keep: `ditto.win*.node`

**For macOS:**

* Ignore: `ditto.win*.node` and `ditto.linux-*.node`
* Keep: `ditto.darwin*.node`

**For Linux:**

* Ignore: `ditto.win*.node` and `ditto.darwin*.node`
* Keep: `ditto.linux-*.node`

This configuration can significantly reduce your executable size by excluding unnecessary platform binaries and development dependencies.
