---
title: Entry points
description: The package entry points of edytor, what each exports, and where each can run, from the browser to Node and Cloudflare Workers, plus the Notion theme stylesheet.
icon: package
---

The `edytor` package has four code entry points and one stylesheet. Only the root contains Svelte components; the CRDT entries have no Svelte in their import graph and run in Node and in Cloudflare Workers.

| Import | Contains | Runs in |
| --- | --- | --- |
| `edytor` | The `<Edytor>` component, bundled plugins, handles, the document API, sync factories | A Svelte bundler (SvelteKit, Vite) |
| `edytor/crdt/edytor` | The document API and its types, `bindCrdt`, awareness, the wire protocol helpers | Browser, Node 22+, Workers |
| `edytor/crdt` | The vendored CRDT engine itself (Yjs v14 fork) | Browser, Node 22+, Workers |
| `edytor/cloudflare` | `DocumentRoom` (a Durable Object), `attachDocument` (for your own Durable Object), `routeDocumentSocket` with `requestedReplica`, and `closedSocket` | Cloudflare Workers only |
| `edytor/themes/notion.css` | The [Notion theme](/docs/customization/styling#notion-theme) stylesheet | Any bundler that imports CSS |

No other path is exported. Imports such as `edytor/dist/...` or `edytor/crdt/vendor/...` fail with `ERR_PACKAGE_PATH_NOT_EXPORTED`.

## `edytor`

The root entry is what a Svelte app imports:

```ts title="imports.ts" check
import {
	Edytor, // the component
	useEdytor, // the editor instance from inside the component tree
	Block, Text, InlineBlock, // handle classes
	richTextPlugin, imagePlugin, arrowMovePlugin, // the default plugins
	codePlugin, markdownShortcutsPlugin, createImagePlugin,
	slashMenuPlugin, createSlashMenuPlugin, toolbarPlugin, createToolbarPlugin,
	blockMenuPlugin, createBlockMenuPlugin, blockHandlesPlugin, createBlockHandlesPlugin,
	richTextOperations, richTextPlaceholder, convertToKind,
	createDocument, loadDocument, attachDocument, // the document API
	createIndexeddbSync, createWebsocketSync, clearDocument, // sync factories
	IndexeddbPersistence, WebsocketProvider // provider classes
} from 'edytor';
```

It also re-exports everything from `edytor/crdt/edytor`, so a Svelte app never needs a second import for the document API or its types (`JSONDoc`, `JSONBlock`, `OpResult`, `DocChange`, …).

Because it contains `.svelte` files, the root entry needs a bundler that compiles Svelte. Plain Node cannot import it.

## `edytor/crdt/edytor`

The same document surface without Svelte. Use it on a server, in a script, in a worker or anywhere the component cannot load:

```ts title="headless.ts" check
import { createDocument, defaultSemantics, loadDocument } from 'edytor/crdt/edytor';

const document = createDocument({
	value: { children: [{ type: 'paragraph', content: [{ text: 'hello' }] }] },
	actor: { id: 'user-42', name: 'Ada' },
	semantics: defaultSemantics // the bundled kinds' block roles: no view supplies them here
});

const [block] = document.facade.project().children;
document.transact(() => document.facade.insertText(block.id, 5, ' world'));

const saved = document.encode(); // Uint8Array
const restored = loadDocument(saved);
console.log(restored.facade.toJSON());
```

It exports:

- `createDocument`, `loadDocument`, `attachDocument` and the `EdytorDocument` class. See [the document reference](/docs/reference/document-api).
- The JSON and facade types: `JSONDoc`, `JSONBlock`, `JSONText`, `JSONInlineBlock`, `BlockSpec`, `Destination`, `OpResult`, `DocChange`, `DocAnchor`, `DocPosition`, `RangeView`, `FlowView`, `EdytorDoc`.
- `Awareness`, the sync and provider types (`EdytorSync`, `WebsocketProviderOptions`, …), admission checks, attribution types and the v13 migration types.
- `bindCrdt(Y)`, which binds the providers, migration and sync protocol to an engine you pass in.
- The frame and message helpers a server coordinator needs.

The ready-made sync factories (`createIndexeddbSync`, `createWebsocketSync`) and the provider classes are exported from the root only. Outside Svelte, reach the providers through `bindCrdt`:

```ts title="engine.ts" check
import * as Y from 'edytor/crdt';
import { bindCrdt } from 'edytor/crdt/edytor';

const crdt = bindCrdt(Y);
const doc = crdt.createDoc();
const awareness = new crdt.Awareness(doc);
const provider = new crdt.providers.IndexeddbPersistence('document-id', doc, { awareness });
await provider.whenSynced;
```

## `edytor/crdt`

The raw engine: Edytor's own fork of Yjs v14, pruned to what Edytor uses (documents, nodes, transactions, `UndoManager`, update encoding and merging, state vectors, relative positions).

```ts
import * as Y from 'edytor/crdt';

const merged = Y.mergeUpdates([updateA, updateB]);
```

You rarely need it directly. Reach for it when you pass the engine to `bindCrdt`, or when you handle raw updates (merging, state vectors) yourself.

:::warning
Keep one engine in your app. The `yjs` package on npm is v13 and its updates are not compatible with this engine. Do not create Yjs documents from `yjs` and hand them to Edytor.
:::

## `edytor/cloudflare`

The server side of real-time collaboration: `DocumentRoom`, a Durable Object that coordinates one document; `attachDocument(this, options)`, which hosts a document in any Durable Object of yours; `routeDocumentSocket`, which authorizes a client before its WebSocket upgrade, and `requestedReplica`, which reads the client id the dial sends; and `closedSocket(code, reason)`, which turns a dial away from your own Worker with a close the provider understands (see [authorization](/docs/server/authorization#authorize)).

```ts title="src/worker.ts"
import { DocumentRoom, routeDocumentSocket, requestedReplica } from 'edytor/cloudflare';

export { DocumentRoom };
```

It imports `cloudflare:workers`, so it loads only inside a Worker. It is built on the Worker-safe CRDT entries and has no Svelte or DOM code. Setup is covered in [Server quick start](/docs/server/quick-start) and [Your own Durable Object](/docs/server/extending). Its `attachDocument` is unrelated to the `attachDocument` of `edytor`, which wraps an engine document on the client.

## Bundle size and tree-shaking

- **Import what you render.** Every JavaScript module in the package is free of side effects (`sideEffects` lists only CSS), so a bundler drops the plugins you never import. The code plugin, with TanStack Highlight and its stylesheet, ships only in apps that import `codePlugin`.
- **The engine is pruned.** `edytor/crdt` is Edytor's fork of Yjs v14, cut down to what Edytor runs on. The document API reaches the engine through one fixed object of the symbols it calls, so an app that never imports `edytor/crdt` itself bundles only what those symbols reach. `bindCrdt(Y)` with the whole namespace (`import * as Y from 'edytor/crdt'`) keeps the whole pruned engine.
- **Headless code stays small.** `edytor/crdt/edytor` has no Svelte and no view code: a server route or Worker that reads and edits documents does not pull in the editor.
- **One engine.** Never add the `yjs` package next to Edytor: it is a second, incompatible engine.

## Choosing an entry

- Rendering an editor: `edytor`.
- Reading, converting or editing a document in Node, a SvelteKit server route or a Worker: `edytor/crdt/edytor`.
- Handling raw updates, or passing the engine to `bindCrdt`: `edytor/crdt`.
- Hosting collaboration on Cloudflare: `edytor/cloudflare`.
- Notion's look for the document: `import 'edytor/themes/notion.css'`.
