---
meta:
  title: "Version history"
  parentTitle: "Sync"
  description:
    "Create, preview, and restore meaningful versions of Storage and Yjs
    documents."
---

Version history lets users browse earlier versions of a document and restore
them, like in Google Docs or Figma. Each version is a snapshot of a room,
capturing both its [Storage](/docs/products/sync/storage) and
[Yjs](/docs/products/sync/text-editing/yjs) documents at a point in time. Versions are
separate from
[multiplayer undo/redo](/docs/products/sync/storage#multiplayer-undo-redo),
which tracks each user’s individual changes—a version instead records a
meaningful milestone that anyone can return to later.

<Banner title="Step-by-step guide">

This page is an overview for Storage, for a step-by-step setup guide, and to
learn more about Yjs version history, read
[how to add version history to your app](/docs/guides/how-to-add-version-history-to-your-app).

</Banner>

## Creating versions

Versions can be created automatically at intervals,
[enabled in your project’s dashboard](/docs/guides/how-to-add-version-history-to-your-app#Creating-versions),
or manually from your back end with
[`Liveblocks.createVersionHistorySnapshot`](/docs/api-reference/liveblocks-node#create-version-history-snapshot).
Manual snapshots are useful at meaningful moments, for example:

- When a user publishes, submits, or saves a document.
- Before an [AI agent](/docs/products/sync/agentic-editing) makes a substantial
  change, so users can recover the previous state.
- Before importing or migrating external data.

```ts
import { Liveblocks } from "@liveblocks/node";

const liveblocks = new Liveblocks({
  secret: "{{SECRET_KEY}}",
});

// +++
const { data } = await liveblocks.createVersionHistorySnapshot("my-room-id");
// +++

// { id: "vh_d75sF3..." }
console.log(data);
```

## Listing versions

On the client,
[`useHistoryVersions`](/docs/api-reference/liveblocks-react#useHistoryVersions)
returns the current room’s versions, newest first. Render them with the
ready-made
[`HistoryVersionSummary`](/docs/api-reference/liveblocks-react-ui#HistoryVersionSummary)
and
[`HistoryVersionSummaryList`](/docs/api-reference/liveblocks-react-ui#HistoryVersionSummaryList)
components, which display each version’s authors and date.

```tsx
import { useState } from "react";
import { useHistoryVersions } from "@liveblocks/react/suspense";
import {
  HistoryVersionSummary,
  HistoryVersionSummaryList,
} from "@liveblocks/react-ui";

function VersionsSidebar() {
  const [selectedVersionId, setSelectedVersionId] = useState<string>();
  // +++
  const { versions, isLoading } = useHistoryVersions();
  // +++

  if (isLoading) {
    return <div>Loading versions…</div>;
  }

  return (
    <HistoryVersionSummaryList>
      // +++
      {versions.map((version) => (
        <HistoryVersionSummary
          key={version.id}
          version={version}
          selected={version.id === selectedVersionId}
          onClick={() => setSelectedVersionId(version.id)}
        />
      ))}
      // +++
    </HistoryVersionSummaryList>
  );
}
```

These UI components are optional, but are a helpful starting point.

## Previewing a version

[`useHistoryVersionStorageData`](/docs/api-reference/liveblocks-react#useHistoryVersionStorageData)
returns the Storage data for a version, reconstructed as a read-only
[`LiveObject`](/docs/api-reference/liveblocks-client#LiveObject). Use it to
render a preview before the user decides to restore.

```tsx
import { useHistoryVersionStorageData } from "@liveblocks/react/suspense";

function VersionPreview({ versionId }: { versionId: string }) {
  // +++
  const { data, isLoading } = useHistoryVersionStorageData(versionId);
  // +++

  if (isLoading) {
    return <div>Loading version…</div>;
  }

  // Render a read-only preview of the document at this version
  return <DocumentPreview document={data.toJSON()} />;
}
```

Because an old version may not match your current `Storage` type, the data is
typed as the more permissive `LsonObject`.

## Restoring a version

[`useRestoreToStorageVersion`](/docs/api-reference/liveblocks-react#useRestoreToStorageVersion)
returns a function that restores the room’s Storage to a given version.

```tsx
import { useRestoreToStorageVersion } from "@liveblocks/react/suspense";

function RestoreButton({ versionId }: { versionId: string }) {
  // +++
  const restore = useRestoreToStorageVersion(versionId);
  // +++

  return <button onClick={() => restore()}>Restore this version</button>;
}
```

The restoration is applied as a single change and synchronized to everyone in
the room. Because it’s added to the user’s undo history like any other edit,
restoring is safe—a user who changes their mind can simply undo it.

## Deleting versions

To allow users to remove a version, use
[`useDeleteHistoryVersion`](/docs/api-reference/liveblocks-react#useDeleteHistoryVersion).
Unlike restoring, deletion is permanent and can’t be undone, so it’s best to ask
for confirmation first.

```tsx
import { useDeleteHistoryVersion } from "@liveblocks/react/suspense";

function DeleteButton({ versionId }: { versionId: string }) {
  // +++
  const deleteHistoryVersion = useDeleteHistoryVersion();
  // +++

  return (
    <button
      onClick={() => {
        if (confirm("Permanently delete this version?")) {
          // +++
          deleteHistoryVersion(versionId);
          // +++
        }
      }}
    >
      Delete
    </button>
  );
}
```

## Server-side access

Versions can also be listed from your back end with
[`Liveblocks.getVersionHistory`](/docs/api-reference/liveblocks-node#get-version-history),
which supports pagination, for example to build custom tooling or scheduled
exports.

```ts
import { liveblocks } from "@liveblocks/node";

const liveblocks = new Liveblocks({
  secret: "{{SECRET_KEY}}",
});

// +++
const { data: versions, nextCursor } =
  await liveblocks.getVersionHistory("my-room-id");
// +++

// [{ id: "vh_d75sF3...", createdAt: ..., authors: [...] }, ...]
console.log(versions);
```

---

For an overview of all available documentation, see [/llms.txt](/llms.txt).
