Advanced Topics
DocState and OpLog

Loro - DocState and OpLog

Although not explicitly exposed in the WASM interface, internally in Loro, we distinctly differentiate between:

  • The current state of the document: DocState
  • The edit history of the document: OpLog

During local operations, we update the DocState and record the operations in OpLog. When merging remote updates, we add the new Ops to OpLog and compute a Delta. This Delta is applied to DocState and also emitted as an event.

DocState can switch between different versions, similar to Git's checkout. In this case, we calculate the Delta based on the edit history. The same mechanism applies: the Delta is emitted as an event and applied to DocState.

Impact on Coding:

  • When calling doc.exportFrom(version), we only encode the operations that occurred after the specified version.
  • When calling doc.exportSnapshot(), we encode both OpLog and DocState, providing rapid loading speed (as it doesn't require recalculating the state of DocState).

Attached/Detached Status

As we aim to support a time machine and the ability to load OpLog without state, the version of DocState and the latest version recorded in OpLog may not always match. When they align, it is in an attached state; otherwise, it's in a detached state.

Since we haven't fully developed the details about Version Control, users cannot edit in Detached mode. They must use attach() to return to the latest version to continue editing.

This design is temporary and will be phased out once we have a more refined version control API in place.


In the future, we will provide methods to export/import only OpLog or DocState, as many scenarios don't require both: DocState suffices for quickly returning document states, and OpLog is enough for rapid update synchronization.

To support better version control, the current design regarding Attached/Detached might undergo significant changes or be removed.

To better handle ever-expanding large documents, redundant Operations can slow down encoding/decoding and increase memory usage. We aim to support discarding chosen Operations in OpLogs. We can support discarding all Operations before a specific Version while retaining the DocState corresponding to that version. Operations occurring after that Version can be merged normally, but those concurrent to the version cannot. Our history records include Timestamp information, allowing developers to make informed decisions about necessary reclamation.