Versions
Contents
Every content item keeps a complete, immutable version history. Each edit produces a new, read-only snapshot of the item, so you can reconstruct exactly what the content looked like at any point in time, see who changed it, and roll back to an earlier state. Versions are created automatically — there is nothing to configure.
How versions are created
A new version is committed whenever the stored state of an item changes. The most common triggers are:
| Action | Effect |
|---|---|
|
Create |
The initial version of a newly created item. |
|
Edit |
Any change to the item’s data, metadata, or form values. |
|
Move / rename |
Changing the item’s |
|
Sort |
Changing the manual ordering of child items. |
|
Publish |
Copies the current draft version onto the |
|
Unpublish |
Removes the item from |
|
Mark as ready |
Promoting the workflow state to |
Each version records the audit metadata of the change — the timestamp and the user responsible — so the history doubles as an audit trail.
Versions and branches
Content lives on two branches: draft (the editor’s working copy) and master (the published copy the public sees). Both branches are simply pointers into the same version history:
-
Editing an item adds a version and moves the
draftpointer to it. -
Publishing commits the current
draftversion and moves themasterpointer to that same version.
Because both branches reference the version history, the published item on master and the work-in-progress on draft may point to different versions of the same content. This divergence is what the change state (MODIFIED, MOVED, and so on) describes in Content lifecycle.
The current version of an item on a given branch is identified by its _versionKey, one of the standard content properties:
{
"_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"_versionKey": "f1e2d3c4-b5a6-7890-abcd-ef1234567890", (1)
"_timestamp": "2026-06-15T12:00:00Z", (2)
"modifier": "user:system:editor",
"modifiedTime": "2026-06-15T12:00:00Z"
}
| 1 | _versionKey — identifier of the version this branch currently points to. Comparing the _versionKey of an item on draft versus master tells you whether the published copy is behind the draft. |
| 2 | _timestamp — the time this particular version was committed. |
| In a layered project, only versions created within a given layer are visible in that layer. Versions are not "polluted" by changes inherited from surrounding layers. |
Comparing and restoring
In Content Studio, the Version history panel lists every version of the selected item as a timeline of events (created, edited, published, unpublished, sorted, marked as ready), each stamped with the time and the responsible user. From there an editor can:
-
Compare any two versions to see a field-by-field diff of what changed.
-
Revert to an earlier version, which copies that snapshot into a new
draftversion. Reverting never deletes history — it simply adds a new version on top.
Accessing versions
For headless consumers, the relevant choice is almost always which branch to read, not which historical version. Selecting a branch resolves to that branch’s current version:
-
Query
master(the default) for the published content the public should see. -
Query
draftfor unpublished, in-progress content — for example, to drive a preview.
{
guillotine(branch: "draft") { (1)
get(key: "/site/articles/hello") {
_id
displayName
modifiedTime
}
}
}
| 1 | Without branch, Guillotine reads master. See the Guillotine documentation for branch selection. |
Reading arbitrary points in the version history — listing all versions of an item — is not exposed in the headless query API by default. You may access this functionality through the Content API, and optionally expose it through a Guillotine extension or a custom API. Visit the Enonic Development Kit documentation for details.