Export a dataset
How to export a dataset with the Sanity CLI, what the export archive contains, and how asset binaries are handled.
Exporting a dataset downloads its documents and asset binaries to a local gzipped tarball. It's the usual starting point for migrating content between datasets or projects, taking a point-in-time copy before a risky change, or working with content outside a studio.
This guide explains how to export a dataset with the Sanity CLI, what lands in the archive, how assets are handled, and how to read the warnings an export prints. To load an export back into a dataset, see Importing data.
Prerequisites:
- Read access to the dataset you want to export.
- A signed-in CLI session, from
npx sanity@latest login. Exporting programmatically needs a token instead.
Export a dataset with the CLI
Run the export from your project directory:
npx sanity@latest datasets export production production.tar.gz
pnpm dlx sanity@latest datasets export production production.tar.gz
yarn dlx sanity@latest datasets export production production.tar.gz
bunx sanity@latest datasets export production production.tar.gz
The first argument is the dataset name and the second is the output path. Leave them out and the CLI prompts for both. To export from a project other than the one configured locally, pass --project-id.
The flags that change what the export contains:
--no-assets: Export only non-asset documents, and remove asset references from them.--raw: Export documents as stored, without rewriting asset references.--no-drafts: Export only published versions of documents.--types: Limit the export to a comma-separated list of document types.--mode: How documents are read, eitherstream(the default) orcursor.
For every flag, run npx sanity@latest datasets export --help or see the Datasets CLI command reference.
What the export archive contains
The export is a gzipped tarball. Everything sits under a single directory named for the dataset and the time of the export:
data.ndjson: Every exported document, one JSON object per line.assets.json: A map of asset document IDs to the URLs they were downloaded from.images/: The downloaded image binaries.files/: The downloaded file binaries.
The images/ and files/ directories are always present, and are empty when the export skipped asset binaries. You can import the tarball as it is, or extract it and import data.ndjson on its own. See Importing data.
How assets are exported
By default, the export downloads the binary for every asset document in the dataset. An asset document is any document of type sanity.imageAsset or sanity.fileAsset, and each one is queued for download whether or not another document references it. Assets linked from Media Library are included the same way, because linking creates an asset document in the dataset.
If a download returns HTTP 401, 403, or 404, the export prints ⚠ Asset failed with HTTP 404 (ignoring) with the asset document ID, skips that asset, and continues. The export still completes.
No flag limits the download to referenced assets. The two flags that change asset handling skip binaries rather than filtering them:
--no-assetsskips the binaries, drops the asset documents, and strips asset references from the exported documents. The result isn't a complete copy of the dataset.--rawexports documents as stored, without rewriting asset references. Combine it with--no-assetsto leave the binaries out but keep the references in place.
Linked library assets count toward export size
Linked assets are bundled at full size, the same as assets uploaded directly to the dataset, so a dataset that gets most of its media from a library can still produce a multi-gigabyte export. See Media Library limits and usage details.
Diagnose a 404 during export
A 404 during export is a warning, not a failure. It means an asset document in the dataset has no binary behind it.
The most common cause is a Media Library asset that was unlinked and later deleted. Deleting an asset from the library doesn't remove the asset document that linking created in your dataset. The library blocks deletion while a document still references the asset, so this affects assets that were linked and then went unused. The dataset keeps the asset document, its binary is gone, and the next export reports a 404 for it.
To confirm whether a library asset still exists, take the asset ID from the last segment of the document's media._ref and query the library for it:
const mediaLibraryId = 'MEDIA_LIBRARY_ID'
const assetId = 'ASSET_ID' // The last segment of media._ref
const token = process.env.SANITY_API_TOKEN
const query = encodeURIComponent(`*[_type == 'sanity.asset' && _id == '${assetId}']{_id}`)
await fetch(`https://api.sanity.io/v2025-02-19/media-libraries/${mediaLibraryId}/query?query=${query}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})An empty result array means the asset is no longer in the library, which is what produces the 404.
Export a large dataset
Dataset exports are billed against your API quota. Documents are streamed to keep that cost down, and the --mode flag chooses how they're read:
stream(the default) reads the whole dataset in one request. The result is consistent, but it can be slow on large datasets.cursorpages through the dataset. It's faster on large datasets and uses more requests, and it can miss changes if someone makes an edit while the export runs.
Export programmatically
The CLI command wraps the @sanity/export package. Use the package directly when you need to filter or transform documents as they're exported, or to run exports from your own tooling.
npm install @sanity/export @sanity/client
pnpm add @sanity/export @sanity/client
yarn add @sanity/export @sanity/client
bun add @sanity/export @sanity/client
import {createClient} from '@sanity/client'
import {exportDataset} from '@sanity/export'
const client = createClient({
projectId: 'YOUR_PROJECT_ID',
dataset: 'production',
apiVersion: '2026-09-09',
token: process.env.SANITY_API_TOKEN,
useCdn: false,
})
const result = await exportDataset({
client,
dataset: 'production',
outputPath: './production.tar.gz',
onProgress: (progress) => console.log(progress.step),
})
console.log(`Exported ${result.documentCount} documents and ${result.assetCount} assets`)The client must be created with a token, and outputPath is required. Pass '-' to write to stdout, or a writable stream to send the archive somewhere else. The same options the CLI exposes as flags are available here, including assets, raw, drafts, types, and mode.
To export a Media Library rather than a dataset, call exportMediaLibrary with a mediaLibraryId in place of dataset. Passing both throws.
Use the named export
The package's default export is deprecated and will be removed in a future release. Import the named exportDataset function instead.
Other ways to export
The Export API streams a dataset's documents as newline-delimited JSON over HTTP. It doesn't download asset binaries, so use it when you want document data alone. See the Export API reference.
Backups are retained copies of a dataset that Sanity takes on a schedule, rather than a file you download on demand. Use them for recovery instead of migration. See Backups.