Entry versioning, comparison, and rollback
Entry versioning, comparison, and rollback
TL;DR
- Every save creates a new, immutable, complete snapshot of the entry -- not a diff. Any version can be loaded independently.
- Restoring a previous version creates a new version (it never overwrites history), preserving a full audit trail for compliance.
- Restoring does not republish: the restored content updates the draft, and you'll want to explicitly publish it to push changes live.
- The Version API provides programmatic access to the full history, enabling automated compliance reporting and change audits.
Every time you save an entry in Contentstack, the system creates a new version. Not a diff. Not a delta. A complete, immutable snapshot of the entry at that moment. This happens automatically, silently, and without any action from the editor beyond clicking Save. Version 1 is the initial creation. Version 2 is the first edit. Version 47 is the forty-seventh save. The version number only increments; it never resets, and previous versions are never overwritten.
This versioning behavior is not a convenience feature bolted on for power users. It is the foundation of content auditability, error recovery, and regulatory compliance. In industries like pharmaceuticals, finance, and healthcare, the ability to prove exactly what content was published at a specific point in time and who changed it is a legal requirement, not a nice-to-have.
How versioning works in practice
When an editor opens an entry and makes changes, nothing happens to the version history until they click Save. The act of saving creates a new version with the complete state of all fields. If an editor opens an entry, changes the title, and saves, version N+1 contains the new title plus the unchanged values of every other field. If they then change a description field and save again, version N+2 contains the new description, the previously changed title, and all other field values.
This means any version is a self-contained snapshot. You do not need to reconstruct it from a chain of diffs. You can load version 12 and see exactly what every field contained at that point.
Version metadata
Each version carries metadata beyond the field values:
- Version number: the sequential integer identifier.
- Created by: the user who performed the save.
- Created at: the timestamp of the save.
- Locale: the locale in which the save occurred (localized entries have independent version histories per locale).
This metadata provides the audit trail. For a pharmaceutical company tracking changes to drug information pages, the combination of who, when, and what changed constitutes a compliance record.
Viewing version history
To access the version history of any entry:
- Open the entry in the entry editor.
- Click the Versions tab (or the version indicator, depending on UI layout).
- The version list appears, showing each version with its number, author, and timestamp.
The version list is ordered from newest to oldest. Each version is clickable, allowing you to inspect the complete state of the entry at that point in time.
Comparing versions
Contentstack provides a diff view that shows field-by-field changes between any two versions. This is invaluable when you need to understand what changed and when.
To compare versions:
- Open the entry's version history.
- Select two versions to compare.
- The diff view highlights additions, deletions, and modifications for each field.
The comparison is field-level, not character-level. If a Rich Text Editor field changed, the diff shows the old and new content for that field. If a reference field was updated, the diff shows which references were added or removed. Fields that did not change between the two versions are either hidden or shown as unchanged, depending on the view settings.
What the diff view reveals
Consider a product entry for a pharmaceutical company. Between version 5 and version 8, the diff might expose targeted field variances across compliance values:
| Field | Version 5 | Version 8 |
| dosage_instructions | "Take once daily with food" | "Take once daily with or without food" |
| side_effects | (unchanged) | (unchanged) |
| regulatory_status | "Pending review" | "Approved - FDA 2025-03-15" |
| last_reviewed_by | "Dr. Smith" | "Dr. Patel" |
This view immediately answers the question: "What changed between the version that was under review and the version that was approved?" For compliance purposes, this diff is a reviewable artifact.
Restoring a previous version
When a content error needs to be corrected quickly, or a recent change proves problematic, restoring a previous version is the fastest recovery path.
To restore a version:
- Open the entry's version history.
- Navigate to the version you want to restore.
- Click Restore on that version.
Critically, restoring a version does not delete any history. It does not rewind the version counter. Instead, it creates a new version with the content from the selected historical version. If the entry is currently at version 10 and you restore version 7, the entry moves to version 11, which contains the exact content from version 7. Versions 8, 9, and 10 remain in the history, fully accessible.
This non-destructive behavior is essential for audit compliance. Restoration is itself a tracked event. You can always see that version 11 was a restoration of version 7, and you can still inspect versions 8 through 10 to understand what happened between the original and the restoration.
Common pitfall:
Restoring a previous version does not automatically publish it. If you restore and forget to publish, the live site continues serving the old (incorrect) content even though the draft looks correct in the entry editor.
Restoring does not republish
Restoring a version updates the draft state of the entry. It does not automatically publish the restored content. After restoration, you'll want to explicitly publish the entry to the desired environment for the change to be reflected on the live site. This separation is intentional: it gives teams a chance to verify the restored content before it goes live, rather than blindly pushing a historical snapshot to production.
For the pharmaceutical example, if a drug information page was updated with incorrect dosage information (version 10), the process would follow this flow loop:
- Identify the last known correct version (version 9).
- Restore version 9, creating version 11.
- Review version 11 to confirm correctness.
- Publish version 11 to the production environment.
Each step is auditable. The compliance team can trace exactly when the error was introduced (version 10), when it was corrected (version 11), and when the correction reached the live site (the publish event).
The Version API
Version history is accessible programmatically through the Content Management API. This enables automated auditing, compliance reporting, and integration with external change management systems.
Fetching all versions of an entry
// get-versions.ts - retrieve version history for a drug information entry
const contentTypeUid = "drug_information";
const entryUid = "blt_matrix_link_bracelet";
const response = await fetch(
`https://api.contentstack.io/v3/content_types/${contentTypeUid}/entries/${entryUid}/versions`,
{
headers: {
api_key: process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY!,
authorization: process.env.NEXT_PUBLIC_CONTENTSTACK_MANAGEMENT_TOKEN!,
},
}
);
const { versions } = await response.json();
versions.forEach((version: any) => {
console.log(
`v${version._version} | ${version.updated_at} | ${version.updated_by}`
);
});Fetching a specific version
// get-specific-version.ts - retrieve version 7 for compliance review
const contentTypeUid = "drug_information";
const entryUid = "blt_matrix_link_bracelet";
const versionNumber = 7;
const response = await fetch(
`https://api.contentstack.io/v3/content_types/${contentTypeUid}/entries/${entryUid}/versions/${versionNumber}`,
{
headers: {
api_key: process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY!,
authorization: process.env.NEXT_PUBLIC_CONTENTSTACK_MANAGEMENT_TOKEN!,
},
}
);
const { entry } = await response.json();
console.log(`Version ${versionNumber} title: ${entry.title}`);
console.log(`Dosage: ${entry.dosage_instructions}`);
console.log(`Regulatory status: ${entry.regulatory_status}`);Building an automated audit report
// audit-report.ts - generate a compliance report for all changes in a date range
const contentTypeUid = "drug_information";
const entryUid = "blt_matrix_link_bracelet";
const auditStart = "2025-01-01T00:00:00.000Z";
const auditEnd = "2025-06-30T23:59:59.000Z";
const response = await fetch(
`https://api.contentstack.io/v3/content_types/${contentTypeUid}/entries/${entryUid}/versions`,
{
headers: {
api_key: process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY!,
authorization: process.env.NEXT_PUBLIC_CONTENTSTACK_MANAGEMENT_TOKEN!,
},
}
);
const { versions } = await response.json();
const auditWindow = versions.filter((v: any) => {
const date = new Date(v.updated_at);
return date >= new Date(auditStart) && date <= new Date(auditEnd);
});
console.log(`Audit period: ${auditStart} to ${auditEnd}`);
console.log(`Total changes: ${auditWindow.length}`);
auditWindow.forEach((v: any) => {
console.log(` v${v._version} | ${v.updated_at} | Changed by: ${v.updated_by}`);
});This kind of programmatic access turns Contentstack's version history into a data source for compliance dashboards, change management tickets, and regulatory filing evidence.
How publishing relates to versions
The relationship between versions and publishing is straightforward but frequently misunderstood:
- Publishing always publishes the current version. When you click Publish on an entry, the version that is currently active (the latest saved version) is what gets published.
- Publishing does not create a new version. The act of publishing is a distribution event, not a content change.
- Restoring a version changes the current version but does not publish. After restoring, the entry's draft state reflects the restored content, but the live (published) content remains whatever was last published until you explicitly publish again.
This means the published content and the current draft content can be different versions. An editor might be working on version 12 (draft) while version 10 is still the published version on production. This is normal and expected. The publishing action bridges the gap when the draft is ready.
Asset versioning
Assets in Contentstack also maintain version history. When you upload a new file to an existing asset, the previous file is preserved as a historical version. This applies to images, PDFs, videos, and any other file type managed as an asset.
Asset versioning behaves similarly to entry versioning:
- Each upload creates a new version.
- Previous versions are retained and accessible.
- You can restore a previous asset version, which creates a new version with the old file.
- Asset versions carry metadata: upload timestamp, user, file size, dimensions (for images).
For the pharmaceutical company, this means that if a product data sheet PDF is updated with incorrect information, the compliance team can restore the previous PDF version without losing the audit trail of the erroneous upload.
Operational Step: One important distinction: asset versions are file-level, not field-level. An asset is primarily its file. When you compare asset versions, you are comparing files (and their metadata), not a structured set of fields like you would with an entry.
Named versions
Contentstack supports setting a name on a version to mark it with a human-readable label. This is useful for identifying significant milestones in an entry's lifecycle without relying solely on version numbers.
For example, after a drug information page passes regulatory review, you might name that version "FDA Approved - March 2025". Later, when reviewing the version history, this label immediately identifies the compliance milestone without requiring the reviewer to open each version and inspect its contents.
Named versions are particularly valuable when version numbers grow large. On an entry with 50+ versions, a named version acts as a bookmark, letting teams quickly locate the approved baseline, the pre-launch state, or the last known good version.
Practical use cases
Rolling back a content error
An editor publishes an entry with a typo in a critical field (a wrong phone number on a contact page). The correction path is clean: open the version history, restore the pre-error state, verify, and publish to production. Total recovery time completes in minutes without manual layout reconstruction.
Comparing before and after a major content update
A marketing team overhauls the homepage content. Two weeks later, conversion rates drop. The product manager asks: "What exactly changed?" The diff view between the pre-overhaul version and the current version shows every field-level change, enabling data-driven analysis of what content changes correlated with the metric shift.
Auditing content changes for compliance
A regulatory body requests evidence of all changes to product safety information over the past year. The Version API provides programmatic access to every version, every timestamp, and every author, enabling automated report generation without manual log review.
Common mistakes
Mistake 1: assuming restore republishes content
An editor restores a previous version expecting the live site to update immediately. It does not. Restoration updates the draft; publishing updates the live site. These are separate actions. Always publish after restoring if you need the change to reach a live environment.
Mistake 2: conflating version numbers with publish events
Version 15 is not necessarily the version that is currently live. The published version might be version 12 if no one has published since version 12. Check the publish details in the entry editor or the publish queue to determine which version is live on each environment.
Mistake 3: ignoring locale-specific version histories
In a localized stack, each locale has its own version history for an entry. Restoring version 5 of the English locale does not affect the French locale's version history. When rolling back content, verify you are operating in the correct locale context, especially in stacks with many locales where the locale selector can be easy to overlook.
Summary
Contentstack's automatic versioning creates a complete, immutable audit trail of every content change. Each save produces a new version. Any two versions can be compared field by field. Any historical version can be restored non-destructively, creating a new version rather than erasing history. The Version API enables programmatic access for compliance reporting and automated auditing. Publishing and versioning are related but distinct operations: versions track content changes, while publishing distributes a specific version to an environment. Understanding this separation is critical for both day-to-day content operations and regulatory compliance scenarios.