Import Sanity
Turn a Sanity dataset export into Snabbsite collections and pages, with a mapping you review and commit. Nothing from the dataset or the schema is executed.
Your client's content already lives in Sanity, and rebuilding twenty properties by hand is not a migration anybody actually performs. This lane moves the content you already have.
It needs two inputs, and the second one is not optional in practice:
- A dataset export, produced by
sanity dataset export. It is NDJSON plus animages/andfiles/folder in a tarball. - Your schema directory, the
defineTypecalls in your own repository. The export says a document has a field calledbody. Only the schema says thatbodyis Portable Text with three custom block types in it.
Your schema files are read as text. They are never imported and never run, so a schema that imports your own React components is still safe to point at. No GROQ is evaluated at any point.
Two steps, and the stop in the middle is the point
The mapping decides what a client's whole content history becomes. Getting it wrong quietly is the failure worth designing against, so the tool proposes and a person confirms.
1. Propose
npx @snabbsajt/cli site import sanity \
--export ./production.tar.gz \
--schema ./sanity/schemas \
--proposeThat writes sanity-mapping.json and stops. Nothing is converted yet.
Every document type is proposed as a collection, a page, or skip. Every
field is proposed as one of the nine collection field types, or as skip with a
note saying why. A field we could not place is present and skipped, never
absent. A missing entry and an unnoticed field look the same in a file, and
that is how content disappears without anybody being told.
2. Review, commit, convert
Open the file. Fix what is wrong. Commit it: from here the conversion is deterministic and re-runnable, which is what lets you iterate on a migration.
npx @snabbsajt/cli site import sanity \
--export ./production.tar.gz \
--schema ./sanity/schemas \
--mapping ./sanity-mapping.json \
--name "Client AB" \
--out ./client-snabbsite
npx @snabbsajt/cli site import approve ./client-snabbsite --yesThen push the package the way you push any other one.
Running it again is the normal case
Import, look at the result, fix the mapping, import again. A row is matched on
its Sanity _id, so a second run updates the row instead of writing a second
copy of the same property.
What happens to a row on the second run:
- Nobody touched it in Snabbsite: updated in place.
- The client edited it in Snabbsite: left exactly as it is, and reported as a conflict. Your push never overwrites their words.
- It is new: added.
- The export stopped carrying it: nothing. Rows are never deleted.
A list's shape follows the same idea: a new optional field is added, and a field that would be removed, retyped, or added as required is held and named. Any of those would break rows the client already wrote.
What comes across, and what is reported instead
- Rich text becomes plain text. A collection field holds text, and our text
fields carry no HTML. Links come across as
text (https://…). Bold and italic are dropped. Every embedded block is listed in the report by name: a picture inside the text, a callout, a YouTube embed, one of your own components. Nothing is invented in its place. - A document mapped to a
pagearrives empty, with its title and its address. Its text is in the report. A Sanity document is data; guessing a hero and three bands out of it would be a worse result than an honest blank page. - Hotspot and crop are reported, not approximated. The full picture comes across. Set the focal point again in Snabbsite if a crop looks wrong.
- Drafts come across hidden. A
drafts.document with no published twin is imported and excluded from publishing, so nothing unfinished goes live. - One language per hemsida. We detect which convention your dataset uses:
per-field objects, one document per language, or the
document-internationalizationplugin. A dataset where two of them look equally likely stops the run and says what it found, because picking one would drop the other's content without telling you. Import the second language as its own hemsida.
More than 200 pictures
One import accepts 200 assets, and a bundle carrying 201 is rejected whole. A
portfolio past that is split for you into run-01, run-02 and so on: import
the first, then merge the rest into the same hemsida. Each row travels with its
own pictures, so no run ever points at an image it does not carry.
Never executed or imported as runtime
GROQ queries, your Studio schema files, Portable Text serializers, custom React block components, Studio structure, desk configuration and workflows. None of it runs, and none of it is imported as code.
This is a migration, not an integration: there is no live sync with Sanity, no read-through to their API, and nothing is ever written back.
Didn't find the answer, or is something wrong here? Tell us.
Last updated on