Originally published on the Cosmic blog.
Every CMS decision is a bet on where your content will live for the next five years. The part teams skip when they make that bet is the exit: what happens if you need to move, and what shape the content arrives in when it gets there.
Content durability is the property that makes that question boring. Your content is durable when you can retrieve all of it, in a structured format, on demand, without filing a support ticket, and rebuild it somewhere else. Most teams assume they have this and find out they do not on the week they need it.
Backup, revision history, and export solve three different failures
These get conflated constantly, and the confusion is expensive because each one covers a failure the others do not.
- Backup is a point-in-time restore back into the same system. It covers "we broke production at 3pm."
- Revision history is a per-object change log inside the system. It covers "someone rewrote the pricing paragraph and we want the old one."
- Export is a complete, structured copy that leaves the system. It covers "we are migrating," "legal needs an archive," and "the vendor changed terms."
A backup does not help you leave. An export does not help you recover a paragraph from yesterday. If you only have one of the three, you have a gap, and it is usually the export.
What "structured" actually has to mean
An export is only useful if the thing you get back can be rebuilt without a human reading it. Six properties matter:
- JSON, not rendered pages. Page HTML is a lossy projection of your content. Field boundaries, types, and relationships are gone the moment it renders.
- The schema, not just the values. Field keys, types, select options, required rules, and validation are what let you recreate the model somewhere else.
- Stable IDs. If identifiers are regenerated on export, every relationship in your content becomes a guess.
- Relationships as references. A post that points at an author and three tags should export those pointers, not flatten them into strings.
- Media you can actually retrieve. File references are worthless without reachable originals.
- Everything, not just what is live. Drafts, scheduled items, and locale variants are content too.
Path 1: the dashboard export
Every Cosmic Bucket can export its content as a JSON file from Bucket > Settings > Import / Export. The export includes Object types, Objects, Media, and folders, which covers the schema and the values in one file. It does not include team members, Object revisions, or backups. That scope is documented on the Buckets documentation page, and the same screen imports a JSON file back into a Bucket, which is how you clone an environment or seed a fresh one.
This is the fastest way to answer the durability question for yourself right now. Run the export, open the file, and check that the six properties above are present. That takes about five minutes and tells you more than any vendor claim.
Path 2: the API on a schedule
A manual export is a snapshot. A scheduled export is an insurance policy. The REST API and the TypeScript SDK let you write the same data to your own storage on a cron, so a current copy always lives somewhere you control.
import { createBucketClient } from '@cosmicjs/sdk';
import { writeFile } from 'node:fs/promises';
const cosmic = createBucketClient({
bucketSlug: process.env.COSMIC_BUCKET_SLUG!,
readKey: process.env.COSMIC_READ_KEY!,
});
async function exportType(type: string) {
const all = [];
const pageSize = 100;
let skip = 0;
while (true) {
const { objects } = await cosmic.objects
.find({ type })
.props('id,slug,title,type,status,locale,metadata,created_at,modified_at')
.status('any')
.limit(pageSize)
.skip(skip);
if (!objects?.length) break;
all.push(...objects);
if (objects.length < pageSize) break;
skip += pageSize;
}
await writeFile(`./export/${type}.json`, JSON.stringify(all, null, 2));
return all.length;
}
const count = await exportType('blog-posts');
console.log(`Exported ${count} objects`);
Two details make the difference between a real export and a partial one. status('any') includes drafts, which a default read leaves out. Requesting metadata explicitly keeps every custom field rather than the summary props.
Commit the output to a private repository or push it to object storage, and you get version history on your content for free. Once your object counts run into the thousands, switch the loop to cursor pagination with after, which the API supports and which is more efficient than paging with large skip offsets.
A read key is enough for this job. An export process never needs write access, and keeping the two keys separate is the cheapest safety measure available.
Path 3: the CLI
For scripting against a terminal rather than an application, the Cosmic CLI reads objects, types, and media and can emit JSON for piping into other tools. It is the shortest route to a one-off dump inside a shell script or a CI job, without standing up a Node project first.
The part people forget: media
Content exports usually succeed. Media migrations are where projects stall, because a JSON file full of CDN URLs is not the same thing as owning the files.
Build the download step into your export job: walk the media references, fetch each original, and store it alongside the JSON. Do that once and your archive is genuinely self-contained.
Two behaviors are worth knowing while you plan this. Replacing a media file keeps the same URL and id, so every reference in your content stays valid after the swap. Deleting media purges it from the CDN and does not update the references pointing at it, so a delete can leave broken links behind in objects you have forgotten about. Audit media before a migration, not after.
If you are relying on transformations rather than storing multiple renditions, the derivative sizes are generated at request time from the original. Keeping the originals is what preserves your ability to regenerate everything later.
Backups and revisions, since export does not cover them
Because the JSON export explicitly excludes revisions and backups, treat those as separate controls, and budget for them. Automatic Backups and Revision History are both add-ons on Cosmic, $99/month each, or $199/month for the bundle that also covers Webhooks and Localization. With Automatic Backups enabled, a backup runs daily, and you can take a snapshot on demand, download it, or restore from it. Revision history is tracked per object.
The practical setup for most teams: backups on for recovery, revisions for editorial mistakes, and a scheduled JSON export for durability. Three controls, three failures, no overlap.
Run the drill once a quarter
An export you have never restored is a hypothesis. Turn it into a fact:
- Run a full export, dashboard or API, whichever your process uses.
- Download every referenced media original into the same archive.
- Import the JSON into a clean Bucket, or stand up a local database from it.
- Point a staging build at the restored data and load ten pages, including one with relationships and one with media.
- Write down what broke and how long it took.
The acceptance test is simple: could a developer who has never seen your setup rebuild a working staging site from the archive alone, in a day, with no access to the original account? If the answer is no, you have found the gap while it is cheap to fix.
Seven questions to ask any CMS before you sign
Bring these to the evaluation call and write down the answers:
- Can I export all content myself, without contacting support?
- Is the export structured JSON, and does it include the schema as well as the values?
- Are object IDs stable across export and import?
- Do relationships export as references I can resolve?
- Are drafts, scheduled content, and locale variants included?
- Can I retrieve every media original programmatically?
- Can the whole thing run on a schedule through the API?
A vendor that answers all seven cleanly is one you can leave, which is exactly why you probably will not need to.
Where Cosmic stands
Content in Cosmic is stored as structured Objects with a defined content model, reachable through the REST API and the TypeScript SDK, with a full JSON import and export in the dashboard and a CLI for scripting. Nothing about the format requires our software to read it. That is the standard worth holding every headless CMS to, including this one.
Start free with a Cosmic account, no credit card required.
Top comments (0)