How to export your data from Sanity

Sanity's CLI exports a dataset as a gzipped tarball with documents, history and asset files, but it skips some assets and does not cover everything in your setup. This guide lists what exports, what does not, and the sequence to get a complete copy out.

On this page

What you can export from Sanity today

If your Sanity renewal, pricing change or residency requirement is forcing a move, start with the export. The sanity dataset export command writes a local gzipped tarball that contains your documents, their document history and your asset files. That archive is the raw material for any migration, and it is the first thing to verify before you commit to a new platform.

The export is a data snapshot, not a copy of the project. It does not include your Studio code, so the React components, desktop tooling and custom input logic you built around your content must be kept in your own repository. Schema definitions also sit in code, so the document types, field rules and validations need to be recovered from your Studio source or rewritten in the target CMS. Users, roles and access settings in the Sanity project, along with webhooks, GROQ-based integrations and any third-party connections, are managed outside the dataset and must be inventoried and rebuilt separately.

Assets deserve a specific check. The CLI skips any asset file that returns a 401, 403 or 404 response, so a successful export does not prove every image and file arrived. Compare the asset count in the archive against your project's asset list and record any gaps. Before you rely on the tarball, confirm with Sanity how the current CLI handles document history, asset retention and the exact archive layout, using the Sanity CLI reference for datasets and your support contact.

Which Sanity data exports and how

This table compares the main Sanity data types you need to move, the method that carries each one out, the format you receive and the limits the documentation confirms. Read each row as a checklist: anything marked as a point to confirm needs an answer from Sanity or a test export before you plan the migration around it. The main takeaway is that the CLI dataset export covers documents, history and assets together, but asset files that return access errors are skipped and must be recovered separately.

Data typeExport methodFormatDocumented limits
Documentssanity dataset export on the datasetNewline-delimited JSON inside a gzipped tarballExports the dataset as a unit, so confirm size limits for very large datasets with Sanity
Document historyIncluded in the dataset exportHistorical revisions stored in the same tarballConfirm how far back history is retained for your plan and whether all revisions are included
Asset filesDownloaded by the dataset exportOriginal asset files alongside the document dataAssets returning 401, 403 or 404 are skipped, so list and recover them separately
Studio source codeNot part of the dataset export; use your Git repositorySchema files and Studio configuration in your codeConfirm the Studio is version controlled, because Content Lake data does not contain schema code
Datasets as a unitOne CLI export per datasetOne tarball per datasetConfirm whether projects with several datasets need one export for each
Access and permissionsNot described in the export documentationNot documented in the export outputConfirm with Sanity which roles, tokens and users must be recreated in the target system
Scheduled or incremental exportsNot documented for the dataset commandFull export each runConfirm whether incremental export is supported before planning repeated syncs

What the dataset export does not carry over

The Sanity dataset export gives you documents, history and most asset files in one tarball, but it leaves behind several things a migration depends on. The gaps below are where teams lose time, so each one needs an owner and a workaround before the export runs.

Assets skipped on access errors

The export skips any asset that returns a 401, 403 or 404 response, so the tarball can look complete while some images or files are missing. Those files still have URLs in your documents, which makes the gap easy to miss. Before you rely on the export, list the asset references in the NDJSON and compare them with the files in the tarball. Re-fetch skipped files from their source, such as the original design or upload archive, and confirm the current access rules with Sanity's CLI reference.

Studio code is separate from content

Sanity Studio is MIT licensed, but the export contains only the content in the dataset. Your Studio components, plugins, custom input widgets and deployment settings live in a repository that the export never touches. If that repository is lost or drifts from the live schema, the content becomes hard to read. Keep the Studio source under version control, record the Studio version you deployed, and store a copy alongside each dataset export.

Schemas that exist only in code

Sanity document types, validation rules, field groups and preview settings are defined in JavaScript or TypeScript, not in the dataset. The NDJSON shows field values but not the rules that produced them, so the target CMS needs a separate schema written from the code. Export the schema files with the dataset, and write down which validations and conditional fields the editors relied on. Treat the schema repository as part of the content archive.

Roles, tokens and integrations

The export carries content, not the people and systems around it. Project members, their roles, API tokens, CORS origins, webhooks and any GROQ-based integrations stay in the Sanity project settings. Record each member, role and token in your access register before cutover, and list every consumer of the Content Lake API so you can repoint or retire it. Confirm the exact scope of what the CLI exports against Sanity's documentation, and never copy tokens into the export archive.

Run a complete export in the right order

This sequence turns a Sanity project into a verified local copy of its documents, history, assets and Studio code, stored where your team controls access. Each step leaves a checkable output, so you know the export is complete before any migration work begins.

  1. Inventory datasets, assets and projects

    List every Sanity project and dataset your organization uses, including staging and development datasets, and note where asset files are referenced from. Confirm which datasets hold production content and which users, tokens and access roles can read them. The output is a short register, owned by a named person, that tells you what must be exported and what can be left behind.

  2. Freeze or record write activity

    Decide whether editors can keep changing content during the export. If you cannot pause publishing, record the time the export starts so you can compare changes afterward. Ask the editorial owner to confirm in writing that no bulk imports or scheduled jobs will run during the window. The output is a dated note in your migration log.

  3. Run the dataset export

    Run the sanity dataset export command from the CLI against the dataset in your register, using a token with read access. The command writes a local gzipped tarball that includes document history and asset files. Keep the command output and the CLI version, since they document what was requested. The output is a single archive file that you copy to controlled storage before anything else runs.

  4. Unpack and count documents

    Extract the tarball and locate the NDJSON document file along with the asset folder. Count the lines in the document file and tally records by document type, including drafts and published versions if your schema uses them. Save these counts in a table. The output is a per-type count sheet that the verification step will compare against the live dataset.

  5. Review the skipped asset list

    Check the export output for assets that returned 401, 403 or 404 responses, because the export skips those files. List each missing asset by its document reference and decide whether to restore access, re-upload from an original source, or accept the loss and record it. Ask the asset owner to confirm each decision. The output is a signed-off list of skipped files with a status for each one.

  6. Download the Studio repository and schema files

    Copy the Sanity Studio source code, including the schema definitions, configuration files and any custom input components, from the version control system that deploys it. Record the commit hash that matches the production Studio. Schemas describe field types and references that the NDJSON data depends on, so you need them to interpret the export. The output is a tagged copy of the repository in your archive.

  7. Store everything in a location you control

    Place the tarball, the unpacked documents, the asset folder, the skipped asset list, the counts and the Studio repository snapshot in storage that your organization owns, with access limited to named roles. Write a manifest listing each file with its checksum. The output is a manifest and a restricted archive that another team could restore from without contacting Sanity.

  8. Verify counts and sampled records against the live dataset

    Compare the per-type counts from the export with counts from the live dataset taken at the same point in time, using a query through the Sanity API or CLI. Pick a sample of records across each document type, including ones with references and Portable Text, and check that their fields match the export. Investigate any gap caused by writes after your recorded start time. The output is a signed verification record stating the match rate and the explained differences.

Turning NDJSON documents and Portable Text into another CMS schema

The export gives you the raw material, but the rebuild happens in the target platform. Each document in the dataset is a line of newline-delimited JSON, so you can read the file with a streaming parser and process records one at a time without loading the whole dataset into memory. Start by listing every _type value in the export and mapping each one to a target collection or content type. Pay close attention to references: Sanity stores links between documents as objects with a _ref field pointing at another document's _id, and those IDs must be rewritten into the target's relationship fields. Build an ID map from source _id to new primary key during the first pass, then resolve references in a second pass so that forward links do not break.

Portable Text is the harder part. Each rich text field is an array of blocks, with spans, marks and mark definitions for links and annotations, and inline or custom object blocks for images and embedded content. Your converter must walk these arrays, translate standard block styles and marks into the target editor's node model, and rewrite asset references to the new file locations. Custom blocks in your Studio schema have no automatic equivalent, so list them early and decide, for each one, whether it becomes a block in the target layout builder or a plain embed. Run the converter on a copy of the export and review a sample of long articles by eye, since subtle issues such as lost link annotations or nested lists show up only in rendered output.

Confirm three things before you commit to a converter design. First, ask the target platform's team how it stores rich text and whether it offers a documented import path for block-based content. For Payload, the migration topic for Payload covers rewriting Studio schemas as collections and converting rich text to Lexical; the Strapi and Directus migration topics in this group cover their own mapping decisions for document types, references and rich text. Second, decide how drafts and document history are handled, because the export includes history but the target may only carry published content. Third, check the Sanity export's asset handling against your records, since assets that returned 401, 403 or 404 during export must be recovered separately. Budget for this conversion work as a one-time project that is priced by schema complexity and the number of custom blocks, and request a written scope that names each content type to be converted.

What to plan before the Sanity contract ends

The export tarball is only one part of leaving Sanity. The cards below cover the timing, access, archive, integration and contract questions that determine whether the export is complete and usable. Work through them early, because each one depends on terms and access that Sanity controls.

Start the export well before renewal

Run a full sanity dataset export as a trial months before the renewal date, not in the final week. A first export shows which assets are skipped, how long the download takes on your network and whether the tarball opens cleanly. Gaps found early leave time to fix tokens, permissions and schema mapping before the contract ends.

Confirm data access under your plan

Ask Sanity in writing what your current plan allows for data access, including document history retention, dataset export and any limits on API use during the export. Plan tiers can change which history is available, so the export you run today may not match what you can retrieve at the end of the term.

Keep a dated, verified archive

Store each tarball with its export date, dataset name, CLI version and a checksum in storage you control. Record which asset requests failed with 401, 403 or 404 responses, since those files were not included. A dated archive gives you a fixed reference point if a later export differs or access ends before the migration is finished.

Inventory tokens and API access

List every API token, its role and the services that use it, including the Studio, front ends, build hooks, scheduled jobs and third-party tools. Each token must be revoked or rotated when Sanity access ends, and any system still calling Content Lake will fail. Keep this list with your cutover checklist so no integration is left pointing at the old project.

Map webhooks and integrations

Identify every webhook, GROQ-based query, preview link and connected service, such as search indexing, translation tools and image pipelines. Some depend on Content Lake events that a self-hosted platform does not emit in the same way. Document each one with its owner so you can rebuild or replace it in the target CMS.

Agree data return and deletion terms

Ask your legal or procurement team to confirm the return format, the window for delivering your data after termination and the deletion obligations Sanity applies to stored content and backups. Get these terms from Sanity's written contract, not from documentation or a sales conversation. Pricing and fees for data return should also be confirmed in the same written terms.

Questions buyers ask before exporting from Sanity

Can our own engineers run the Sanity export, or do we need outside help?

Your own engineers can run the export. The sanity dataset export command writes a local gzipped tarball that includes document history and asset files, so the extraction step is small. The effort sits in what happens after the export: mapping document types to another CMS's schema, converting Portable Text and re-uploading assets. Teams with a developer who knows both the Studio schemas and the target CMS often handle the export in-house and bring in outside help only for the mapping and import. Confirm the Sanity CLI version, the dataset name and whether you hold a token with read access to every asset before you start.

What drives the cost of rebuilding our content model after export?

Three inputs drive most of the rebuild cost: schema complexity, Portable Text volume and asset count. Schema complexity covers how many document types, nested objects and references you have, since each one becomes a collection, table or relation in the target system. Portable Text volume matters because rich text blocks, custom marks and embedded components must be converted, and the more custom blocks you use, the more converter rules you write and test. Asset count drives the time spent downloading, checking and re-uploading files. Ask any provider to price these three inputs separately in a written scope, and ask how they will test a sample of documents before the full run.

How long does a Sanity export and content migration take?

The timeline depends on the scope, and no figure is supplied for it here. The main variables are the number of document types, the amount of Portable Text with custom components, the number of assets, and how many editors must review content after the import. Editorial review often takes longer than the technical import. Ask for a written plan that separates the export, schema mapping, import, validation and editor sign-off, and ask which of those steps depend on your team's availability. Confirm the dates of any content freeze you need before the cutover.

What does the team need to provide for the export and rebuild?

The team needs access and decisions more than tooling. You need a Sanity project with a token that can read the dataset, a copy of the Studio schema code, and a named owner who can answer questions about the content model. You also need the target environment ready, with a database, storage for assets and a deployment path for the new CMS. Editors should identify which content is live, which is draft and which is out of date, so you do not migrate material nobody uses. Confirm who signs off on the field mapping and who approves the final import.

Can a non-developer run the Sanity dataset export?

A non-developer can run the export command if someone gives them the project ID, dataset name and a token with the right permissions, and the command runs from a terminal on a machine with the Sanity CLI installed. The output is a file, not a working site, so the harder work is reading the NDJSON documents and converting them. A non-developer can check that the tarball exists and review a sample of documents, but schema mapping, Portable Text conversion and asset handling need a developer. Treat the export as a single step in a larger project and keep the export file in a secure, access-controlled location.

Can we recover assets that the export skipped?

Yes, usually, but the recovery depends on why the asset was skipped. The Sanity CLI skips assets that return a 401, 403 or 404 response during the export. A 401 or 403 often means the token lacks permission, so re-running the export with a token that has read access may fix it. A 404 means the asset file is no longer available at the stored location, so it needs a separate search in your own backups or source files. Ask the team to log every skipped asset, count them by response code and decide which ones must be restored before go-live.

Does the export preserve everything, including document history?

The export includes document history and asset files, but a copy of the data is not the same as a working system. Once the tarball is in your hands, you still need to decide which history matters in the new CMS, since most target platforms store versions differently. Also confirm that the export covers all datasets you use, that Studio customizations and plugin configuration are kept in code, and that access rules and editor roles are recreated manually in the new system. Ask your provider to list what the export carries over and what the team must rebuild by hand.

How to prove the export is complete

Treat the export as unproven until you have reconciled it against the live dataset. Start by counting documents by _type in the source dataset and in the unpacked export, then compare the two lists type by type. Any gap, including draft documents and document types that only appear in history, needs an explanation before you move on. Next, confirm the asset side. The sanity dataset export command skips asset files that return 401, 403 or 404 responses, so the export can succeed while some images or files are missing. Compare the asset references in your documents against the files actually present in the tarball, and write every skipped asset to a log with its document ID and the response code. Those entries are your remediation list, not a footnote.

Documents are only useful if their relationships survive. Pick a sample of records that contain references and Portable Text, including nested references inside blocks and inline objects, and check them by hand in the target schema once the data is loaded. Verify that each _ref resolves to a record that exists, that rich text renders with its marks, links and embedded assets intact, and that the document history for a sample of records matches what you expect. Record the sample, the checks and the results. Where a sampled record fails, widen the sample before you accept the export.

Keep a restore test in a separate environment, and run it before your subscription ends or access is reduced. Restoring the tarball into an isolated stack shows whether the export is usable, which is a stronger claim than having a file on disk. Your compliance owners should own the retention plan: what must be kept, for how long, where it is stored, who can access it and how deletion is evidenced. DeployOpen can help prepare the verification scripts, logs and evidence, but the retention decision and any sign-off belong to your organization and its auditors.

What happens after the export lands

The export gives you a complete copy of the dataset, but it is not a working site yet. This sequence turns the tarball into a target CMS that editors can use, and it ends only when content has been checked against the source and a rollback path is in place.

  1. Verify the export before touching the target

    Before any import, confirm the tarball is complete: the documents file, the document history, and the asset files that the export did not skip. Your engineers should list every asset that returned a 401, 403 or 404 during export, because the CLI skips those and they will not appear in the archive. Record the document counts per type and the asset inventory as your baseline. The step is done when you have a signed-off inventory of what was exported and what was missed, and an owner for each missing asset.

  2. Stand up the target environment

    Your platform team provisions the target CMS inside your own cloud account, data center or private network, along with its database, object storage for assets, a staging deployment and access controls. Use a non-production environment first so import runs can be repeated. Confirm the database engine and runtime versions against the target's current installation requirements, and set up backups before the first import. The step is done when an empty instance boots, staging is reachable only by approved users, and a restore from backup has been tested.

  3. Map schemas and convert content

    Translate each Sanity document type into a collection, content type or table in the target, and map references between documents to relationships in that system. Decide how Portable Text blocks become the target's rich text format, and document any fields that have no direct equivalent. Engineers and a content lead should review the mapping together, using a sample of real records from each type. The step is done when every document type has an approved mapping, a conversion script runs against the sample without errors, and the converted sample renders correctly in the target.

  4. Import documents and assets

    Load the converted documents into staging, then upload the asset files and rewrite the references that pointed to Sanity's asset store so they point to the new storage location. Run the import as a repeatable script so it can be rerun after mapping changes. Include the document history only if your target stores it in a form editors can use. The step is done when import counts match the baseline from the first step, every asset reference resolves, and the exceptions list contains only the items you already tracked.

  5. Rebuild editor workflows and access

    Recreate the editing experience your team relies on: draft and publish states, preview, user roles, and any approval steps that existed in Studio. Account and permission models differ between Sanity and most target systems, so map each editor group to a role and test what each role can publish. Editors should work through their normal tasks on staging. The step is done when a pilot group of editors completes their standard content tasks and the role matrix has been signed off by the content owner and security team.

  6. Run parallel content checks

    Compare the source and the target while both are live for review. Check document counts, sample records field by field, rendered pages for formatting problems, broken links and missing assets, and any code that queries content through an API. Keep a log of defects with an owner and a status. The step is done when the defect log has no open items that block publishing and the agreed sample checks pass on the final import run.

  7. Cut over with a rollback path

    Schedule the switch of production traffic and editor work to the new CMS, after a final import from the frozen Sanity dataset. Keep Sanity in read-only operation and retain the export tarball and the target's backup, so you can return to the previous system if a blocking problem appears. Confirm who makes the go or no-go decision and what triggers a rollback. The step is done when production serves content from the target, editors have confirmed they can publish, and the rollback procedure has been rehearsed.

How DeployOpen works on this

DeployOpen plans and implements the exit from Sanity inside your own infrastructure, so the export, the transformed content and the target CMS stay under your control. We agree the scope in writing before work starts, then deliver and document each step so your team can run the target platform after handover.

How we scope

  • Inventory every dataset, document type, asset folder and webhook your team depends on in Sanity
  • Confirm with you which history, drafts and asset files must move, and which can be left behind
  • Agree in writing the target CMS, hosting location and the Portable Text conversion rules before work starts

How we build

  • Run the dataset export in a controlled environment and keep the gzipped tarball in storage you own
  • Map document types and references to the target schema, then convert Portable Text and re-link assets
  • Log every asset that returns 401, 403 or 404 during export so gaps are known and can be resolved

How we hand over

  • Deliver the schema mapping, conversion scripts and a reconciliation report comparing source and target counts
  • Document how to re-run the export, rebuild the import and verify content before a final cutover
  • Walk your engineers through the target platform's runbook, backup procedure and rollback steps

How we support

  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts
  • Ongoing support, upgrades and continuous testing of the target CMS are available as a retainer
  • Confirm with us during scoping which post-migration tasks fall inside the fixed scope and which move to a retainer

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.