Introduction

Use these guides to add Yjs-based CRDT to your project with Velt. Pick the React Hook wrapper for the fastest integration in React apps, or the core library for other frameworks and vanilla setups.

Setup

Step 1: Install Dependencies

npm:
npm install @veltdev/crdt-react @veltdev/crdt @veltdev/react
yarn:
yarn add @veltdev/crdt-react @veltdev/crdt @veltdev/react

Step 2: Initialize Velt in your app

Wrap your app with VeltProvider. See the full setup in Install Docs.
import { VeltProvider } from '@veltdev/react';

export function Root() {
  return (
    <VeltProvider apiKey="YOUR_API_KEY">
      <App />
    </VeltProvider>
  );
}

Step 3: Create a CRDT store

Create a text store with the React hook.
import { useVeltCrdtStore } from '@veltdev/crdt-react';

function Component() {
  const { store } = useVeltCrdtStore<string>({
    id: 'my-collab-note',
    type: 'text',
    initialValue: 'Hello, world!',
  });
  return null;
}

Step 4: Listen for changes

Listen and subscribe for updates from local and remote peers.
import { useEffect } from 'react';
import { useVeltCrdtStore } from '@veltdev/crdt-react';

function Component() {
  const { store } = useVeltCrdtStore<string>({ id: 'my-collab-note', type: 'text' });

  useEffect(() => {
    if (!store) return;
    const unsubscribe = store.subscribe((newValue) => {
      console.log('Updated value:', newValue);
    });
    return unsubscribe;
  }, [store]);

  return null;
}

Step 5: Update the store value

Apply and update local changes to the store.
import { useVeltCrdtStore } from '@veltdev/crdt-react';

function Component() {
  const { update } = useVeltCrdtStore<string>({ id: 'my-collab-note', type: 'text' });
  const onChange = (e) => update(e.target.value);
  return <input onChange={onChange} />;
}

Step 6: Save and restore versions

Create checkpoints and roll back when needed.
import { useVeltCrdtStore } from '@veltdev/crdt-react';

function Component() {
  const { saveVersion, getVersions, getVersionById, setStateFromVersion } =
    useVeltCrdtStore<string>({ id: 'my-collab-note', type: 'text' });

  async function onSave() {
    const versionId = await saveVersion('Checkpoint');
    console.log('Saved version:', versionId);
  }

  async function onRestoreLatest() {
    const versions = await getVersions();
    if (versions.length === 0) return;
    const latest = versions[0];
    await setStateFromVersion(latest);
  }

  return (
    <div>
      <button onClick={onSave}>Save Version</button>
      <button onClick={onRestoreLatest}>Restore Latest</button>
    </div>
  );
}

APIs

useVeltCrdtStore

React hook to create and sync a collaborative CRDT store.
const {
  value,
  versions,
  store,
  update,
  saveVersion,
  getVersions,
  getVersionById,
  restoreVersion,
  setStateFromVersion,
} = useVeltCrdtStore<string>({
  id: 'my-collab-note',
  type: 'text',
  initialValue: 'Hello, world!',
  debounceMs: 100,
});

value

Current value of the store.
  • Type: T | null
console.log(value);

versions

List of all stored versions.
  • Type: Version[]
console.log(versions);

store

Underlying Velt Store instance.
  • Type: Store<T> | null
console.log(store);

restoreVersion()

Restore the store to a specific version by ID.
  • Params: versionId: string
  • Returns: Promise<boolean>
await restoreVersion('abc123');

update

Update the store value.
  • Params: newValue: T
  • Returns: void
update('New value');

saveVersion

Save a snapshot of the current state as a named version.
  • Params: versionName: string
  • Returns: Promise<string>
await saveVersion('Checkpoint');

getVersions

Fetch all saved versions.
  • Params: none
  • Returns: Promise<Version[]>
const versions = await getVersions();

getVersionById

Fetch a specific version by ID.
  • Params: versionId: string
  • Returns: Promise<Version | null>
const version = await getVersionById('abc123');

setStateFromVersion

Restore the store state from a specific version.
  • Params: version: Version
  • Returns: Promise<void>
await setStateFromVersion(version);

Encryption

You can encrypt CRDT data before it’s stored in Velt by registering a custom encryption provider. For CRDT methods, input data is of type Uint8Array | number[].
async function encryptData(config: EncryptConfig<string>): Promise<string> {
  const encryptedData = await yourEncryptDataMethod(config.data);
  return encryptedData;
}

async function decryptData(config: DecryptConfig<string>): Promise<string> {
  const decryptedData = await yourDecryptDataMethod(config.data);
  return decryptedData;
}

const encryptionProvider: VeltEncryptionProvider<string, string> = {
  encrypt: encryptData,
  decrypt: decryptData,
};

<VeltProvider
  apiKey="YOUR_API_KEY"
  encryptionProvider={encryptionProvider}
/>
See also: setEncryptionProvider() · VeltEncryptionProvider · EncryptConfig · DecryptConfig