If you want to update this page or add new content, please submit a pull request to the Homepage.

Revisions

Revisions provide version control for Yorkie documents, allowing you to save snapshots at specific points in time, browse history, and restore previous states. This guide explains how to integrate revision features into your application.

Overview

Revisions are immutable snapshots of a document's state stored on the server. Each revision contains:

  • Label: A user-friendly identifier (e.g., "v1.0", "Draft", "Final")
  • Description: Optional detailed explanation of what changed
  • Snapshot: The complete document state in YSON format
  • Timestamp: When the revision was created
  • Server Sequence: The document's server sequence number at creation time

Use Cases

  • Version History: Allow users to browse and restore previous document versions
  • Milestone Tracking: Save important states before major changes
  • Audit Trail: Maintain a record of document evolution over time
  • Collaboration Review: Preview changes before accepting them
  • Rollback: Recover from unwanted changes or errors

Before You Begin

This guide assumes familiarity with:

  1. Client and Document basics
  2. YSON format for understanding snapshots

How Revisions Work

When you create a revision:

  1. The server builds the current document state
  2. The state is serialized to YSON format (data only, no CRDT metadata)
  3. The revision is stored with metadata in the database
  4. A RevisionSummary is returned to the client

API Reference

For detailed API documentation, see JS SDK - Document Revisions.

MethodDescription
client.createRevision(doc, label, description?)Create a new revision
client.listRevisions(doc, options?)List revisions with pagination
client.getRevision(doc, revisionId)Get revision details with snapshot
client.restoreRevision(doc, revisionId)Restore document to a revision

Building a Revision UI

This section shows how to build a revision management interface, using patterns from CodePair as a reference.

React Hook Pattern

Create a custom hook to manage revision state and operations:

1import { useState, useCallback, useEffect } from 'react';
2import { Client, Document, RevisionSummary } from '@yorkie-js/sdk';
3
4interface UseRevisionsOptions {
5 client: Client | null;
6 doc: Document<any, any> | null;
7 enabled?: boolean;
8}
9
10export function useRevisions({ client, doc, enabled = true }: UseRevisionsOptions) {
11 const [revisions, setRevisions] = useState<RevisionSummary[]>([]);
12 const [isLoading, setIsLoading] = useState(false);
13 const [error, setError] = useState<Error | null>(null);
14
15 // Fetch revision list
16 const fetchRevisions = useCallback(async (options?: {
17 pageSize?: number;
18 offset?: number;
19 isForward?: boolean;
20 }) => {
21 if (!client || !doc) return;
22
23 setIsLoading(true);
24 setError(null);
25
26 try {
27 const revs = await client.listRevisions(doc, {
28 pageSize: options?.pageSize ?? 50,
29 offset: options?.offset ?? 0,
30 isForward: options?.isForward ?? false, // newest first
31 });
32 setRevisions(revs);
33 return revs;
34 } catch (err) {
35 const error = err instanceof Error ? err : new Error('Failed to fetch revisions');
36 setError(error);
37 throw error;
38 } finally {
39 setIsLoading(false);
40 }
41 }, [client, doc]);
42
43 // Create a new revision
44 const createRevision = useCallback(async (label: string, description?: string) => {
45 if (!client || !doc) {
46 throw new Error('Client or document not available');
47 }
48
49 setIsLoading(true);
50 try {
51 const revision = await client.createRevision(doc, label, description);
52 await fetchRevisions(); // Refresh list
53 return revision;
54 } catch (err) {
55 const error = err instanceof Error ? err : new Error('Failed to create revision');
56 setError(error);
57 throw error;
58 } finally {
59 setIsLoading(false);
60 }
61 }, [client, doc, fetchRevisions]);
62
63 // Get revision with full snapshot
64 const getRevision = useCallback(async (revisionId: string) => {
65 if (!client || !doc) {
66 throw new Error('Client or document not available');
67 }
68 return client.getRevision(doc, revisionId);
69 }, [client, doc]);
70
71 // Restore to a previous revision
72 const restoreRevision = useCallback(async (revisionId: string) => {
73 if (!client || !doc) {
74 throw new Error('Client or document not available');
75 }
76
77 setIsLoading(true);
78 try {
79 await client.restoreRevision(doc, revisionId);
80 await client.sync(); // Ensure changes propagate
81 await fetchRevisions(); // Refresh list
82 } catch (err) {
83 const error = err instanceof Error ? err : new Error('Failed to restore revision');
84 setError(error);
85 throw error;
86 } finally {
87 setIsLoading(false);
88 }
89 }, [client, doc, fetchRevisions]);
90
91 // Load revisions on mount
92 useEffect(() => {
93 if (enabled && client && doc) {
94 fetchRevisions();
95 }
96 }, [enabled, client, doc, fetchRevisions]);
97
98 return {
99 revisions,
100 isLoading,
101 error,
102 fetchRevisions,
103 createRevision,
104 getRevision,
105 restoreRevision,
106 };
107}

Using the Hook

1function RevisionPanel() {
2 const { client, doc } = useYorkie(); // Your Yorkie context
3 const {
4 revisions,
5 isLoading,
6 createRevision,
7 getRevision,
8 restoreRevision,
9 } = useRevisions({ client, doc });
10
11 const handleCreate = async () => {
12 const label = `v${new Date().toISOString().split('T')[0]}`;
13 await createRevision(label, 'Manual checkpoint');
14 };
15
16 const handlePreview = async (revisionId: string) => {
17 const revision = await getRevision(revisionId);
18 // Display revision.snapshot in a preview dialog
19 };
20
21 const handleRestore = async (revisionId: string) => {
22 if (confirm('Restore to this revision? Current state will be replaced.')) {
23 await restoreRevision(revisionId);
24 }
25 };
26
27 return (
28 <div>
29 <button onClick={handleCreate} disabled={isLoading}>
30 Save Revision
31 </button>
32 <ul>
33 {revisions.map((rev) => (
34 <li key={rev.id}>
35 <span>{rev.label}</span>
36 <span>{new Date(rev.createdAt).toLocaleString()}</span>
37 <button onClick={() => handlePreview(rev.id)}>Preview</button>
38 <button onClick={() => handleRestore(rev.id)}>Restore</button>
39 </li>
40 ))}
41 </ul>
42 </div>
43 );
44}

Previewing Snapshots

Use the YSON parser to convert snapshots into readable data:

1import { YSON } from '@yorkie-js/sdk';
2
3async function previewRevision(revisionId: string) {
4 const revision = await client.getRevision(doc, revisionId);
5
6 if (revision.snapshot) {
7 // Parse YSON to get document data
8 const data = YSON.parse<YourDocType>(revision.snapshot);
9
10 // For Text fields, convert to plain string
11 if (data.content) {
12 const plainText = YSON.textToString(data.content);
13 console.log('Document content:', plainText);
14 }
15 }
16}

Restoration Flow

When restoring a revision, the server:

  1. Loads the revision's YSON snapshot
  2. Creates a new document state from the snapshot
  3. Applies the change through the CRDT merge process
  4. Syncs the restored state to all connected clients

Restoring replaces the entire document state. Consider creating a new revision before restoring to preserve the current state as a backup.

Auto-Revisions

Yorkie can automatically create revisions during snapshot creation. This is controlled by the auto-revision-enabled project setting.

SettingDefaultDescription
auto-revision-enabledtrueAutomatically create revisions during snapshots

When enabled:

  • Revisions are created automatically during garbage collection snapshots
  • Labels follow the format: snapshot-{serverSeq}
  • Descriptions: Auto created revision of snapshot #{serverSeq}

Configure via the Dashboard or Admin API. See Resources for details.

Best Practices

When to Create Revisions

  • Before major edits: Save state before significant changes
  • At milestones: Mark completion of features or sections
  • Periodically: For long editing sessions, create time-based checkpoints
  • Before restore: Always save current state before restoring an old revision

Labeling Conventions

Use consistent, descriptive labels:

PatternExampleUse Case
Version numbersv1.0, v2.1Release milestones
Date-based2024-01-15, backup-2024-01-15Time-based checkpoints
Feature namesauth-complete, refactor-doneFeature milestones
Descriptivebefore-review, final-draftWorkflow stages

Storage Considerations

  • Revisions store full document snapshots, not deltas
  • Each revision consumes storage proportional to document size
  • Use auto-revisions judiciously for large documents
  • Consider periodic cleanup of old revisions if storage is a concern

Permissions

Revision operations require appropriate document permissions:

OperationRequired Permission
CreateWrite access
ListRead access
GetRead access
RestoreWrite access