# Migrating from dotlottie-js
A code-for-code guide to moving a project from dotlottie-js to dotlottie-io, covering API differences, package changes, and what's new.

# Migrating from dotlottie-js

This guide is for teams with an existing [`dotlottie-js`](/docs/tools/dotlottie-js) integration who want to move to `dotlottie-io`.

## Why migrate

`dotlottie-io` does the same job as `dotlottie-js` — creating, reading, and manipulating `.lottie` files — with a Rust core exposed through Node.js and WebAssembly bindings. Compared to `dotlottie-js`, it offers:

- A fully **synchronous** API for local file operations (no `Promise`-based `build()` step)
- A **lazy reader** (`DotLottieReader`) for inspecting large archives without loading everything into memory
- **Password-protected, AES-256 encrypted** archives
- **Cross-reference query methods** (which animations use this theme/asset/state machine)
- A shared Rust core with other parts of the dotLottie ecosystem

`dotlottie-io` will supersede `dotlottie-js`, so it's best to migrate earlier rather than later.

## 1. Package name change

This is the easiest thing to miss: the npm scope changes.

```diff
- npm install @dotlottie/dotlottie-js
+ npm install @lottiefiles/dotlottie-io
```

```diff
- import { DotLottie } from '@dotlottie/dotlottie-js'
+ const { DotLottie } = require('@lottiefiles/dotlottie-io')
```

`dotlottie-io`'s Node.js package is CommonJS-first (`require`), though it also works with `import` under Node's interop. The browser build is ESM-only and requires an explicit `init()` call — see [Platform Notes](/docs/tools/dotlottie-io/guides/platform-notes).

## 2. At a glance

| Aspect                          | dotlottie-js                                                      | dotlottie-io                                                                                        |
| ------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| **Core**                        | Pure JavaScript/TypeScript                                        | Rust, with Node (N-API) and WASM bindings                                                           |
| **API style**                   | Async, single fluent `DotLottie` class                            | Sync, split across `DotLottie` / `DotLottieBuilder` / `DotLottieReader` / `DotLottieMerger`         |
| **Build step**                  | Required: `await dotlottie.build()` before export                 | Not required — `DotLottieBuilder.build()` is the construction step itself, and is synchronous       |
| **URL fetching**                | Built in (`addAnimation({ url })`)                                | Not built in — fetch yourself, then pass the bytes                                                  |
| **Browser download**            | Built in (`.download(filename)`)                                  | Not built in — build a `Blob` from `toBytes()` yourself                                             |
| **Lazy/low-memory reading**     | ❌                                                                 | ✅ `DotLottieReader`                                                                                 |
| **Password protection**         | ❌                                                                 | ✅ AES-256, via a `password` argument on I/O methods                                                 |
| **Cross-reference queries**     | ❌                                                                 | ✅ `animationsUsingTheme`, `animationsUsedByStateMachine`, `assetReferences`, `animationsUsingAsset` |
| **Merge collision handling**    | `merge()` throws on any duplicate ID                              | `DotLottieMerger` with a chosen `MergeStrategy` (`Rename`/`Skip`/`Fail`)                            |
| **Standalone asset attachment** | Not exposed on `DotLottie` — assets come from animation JSON only | ✅ `addImage`/`addFont`/`addAudio` as first-class methods on `DotLottie`                             |
| **Font assets**                 | Extracted from animation JSON only                                | Same, plus explicit `addFont`/`getFont`/`fontFilenames`                                             |

## 3. Code-for-code examples

### Creating and saving a file

**dotlottie-js:**

```javascript
import { DotLottie } from "@dotlottie/dotlottie-js";

const dotlottie = new DotLottie();
dotlottie.addAnimation({ id: "hero", data: heroLottieJson });
await dotlottie.build();

const buffer = await dotlottie.toArrayBuffer();
await writeFile("output.lottie", Buffer.from(buffer));
```

**dotlottie-io:**

```javascript
const { DotLottieBuilder } = require("@lottiefiles/dotlottie-io");
const { writeFileSync } = require("node:fs");

const builder = new DotLottieBuilder();
builder.addAnimation("hero", JSON.stringify(heroLottieJson));

const dl = builder.build(); // synchronous
writeFileSync("output.lottie", dl.toBytes()); // synchronous
```

Note the different construction pattern: `dotlottie-js` mutates a `new DotLottie()` in place and finalizes it with `build()`; `dotlottie-io` queues content on a `DotLottieBuilder` and `build()` _produces_ a `DotLottie`.

### Loading and inspecting a file

**dotlottie-js:**

```javascript
import { DotLottie } from "@dotlottie/dotlottie-js";

const dotlottie = await new DotLottie().fromArrayBuffer(arrayBuffer);
console.log(dotlottie.animations.length);
```

**dotlottie-io:**

```javascript
const { DotLottie } = require("@lottiefiles/dotlottie-io");

const dl = DotLottie.fromBytes(buffer); // synchronous, no await
console.log(dl.animationIds().length);
```

### Adding a theme

**dotlottie-js:**

```javascript
dotlottie.addTheme({
  id: "dark",
  data: { colors: { primary: "#FFFFFF" } },
});
```

**dotlottie-io:**

```javascript
dl.addTheme("dark", "Dark Theme", JSON.stringify({ rules: [] }));
```

Note the theme data shape itself differs too — `dotlottie-io` (and dotLottie V2 generally) expects a `{ rules: [...] }` structure, not the ad hoc `{ colors: {...} }` shape some `dotlottie-js` examples use. Check your theme JSON against the [V2 theming spec](https://dotlottie.io/) if you're carrying data over directly.

### Merging files

**dotlottie-js:**

```javascript
const merged = dl1.merge(dl2, dl3); // throws on any duplicate ID
await merged.build();
```

**dotlottie-io:**

```javascript
const { DotLottieMerger, MergeStrategy } = require("@lottiefiles/dotlottie-io");

const merger = new DotLottieMerger(MergeStrategy.Rename); // choose collision behavior
const merged = merger.merge(dl1, [dl2, dl3]); // synchronous, ready immediately
```

## 4. What doesn't carry over directly

- **`addAnimation({ url: '...' })`** — `dotlottie-js` fetches the URL during `build()`. `dotlottie-io` has no network layer at all: fetch the JSON yourself (`fetch(url).then(r => r.arrayBuffer())` or Node's `http`/`https`), then call `addAnimation(id, buffer)`.

- **`.download(filename)`** — `dotlottie-io` doesn't touch the DOM. In the browser, build the download yourself from the bytes `toBytes()` returns:

  ```javascript
  const bytes = dl.toBytes();
  const blob = new Blob([bytes], { type: "application/zip" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = "output.lottie";
  a.click();
  URL.revokeObjectURL(url);
  ```

- **Author/description/keywords metadata** — these were `dotlottie-js` v1 (pre-1.0.0) fields (`setAuthor`, `setDescription`, `setKeywords`, `setRevision`). They were already dropped from `dotlottie-js`'s own v2 manifest schema, so if you're migrating from a `dotlottie-js` v2 project this doesn't change anything. If you're still on pre-1.0.0 `dotlottie-js`, see its own [migration guide](/docs/tools/dotlottie-js/guides/migration) first for the v1→v2 manifest changes, since the same fields are absent from `dotlottie-io`'s manifest too.

- **Playback fields on animations** (`autoplay`, `loop`, `speed`, `direction`, `hover`, `intermission`, `themeColor`) — also already dropped in `dotlottie-js` v2's `AnimationOptions` in favor of player-side configuration; `dotlottie-io`'s `AnimationOptions` matches this (see [Managing Animations](/docs/tools/dotlottie-io/core-concepts/animations)).

## 5. New capabilities worth adopting

Once the port is functionally complete, consider using what `dotlottie-io` adds:

- **[`DotLottieReader`](/docs/tools/dotlottie-io/api/dotlottie-reader-class)** for any code path that only needs to inspect a `.lottie` file, not load and re-serialize it — see [How to Read a .lottie File](/docs/tools/dotlottie-io/guides/reading-a-lottie-file).
- **Password protection** for any `.lottie` files distributed outside your control — see [How to Password-Protect a .lottie File](/docs/tools/dotlottie-io/guides/password-protecting-files).
- **Cross-reference queries** for build-time linting (unused assets, orphaned themes) — see [How to Query Relationships](/docs/tools/dotlottie-io/guides/querying-relationships).

## General recommendations

1. Update the package name and import style first, then run your existing test suite against the new synchronous API shape — most failures will be `await`s that need removing or restructuring, not logic changes.
2. Replace any `addAnimation({ url })` usage with an explicit fetch step.
3. Replace any `.download()` usage with the `Blob`/anchor pattern shown above.
4. If you use themes, verify their JSON shape matches the `{ rules: [...] }` structure `dotlottie-io` expects.

Next up: [API Reference](/docs/tools/dotlottie-io/api)
