Migrate from Sanity to Directus

What moves cleanly from a Sanity dataset into a self-hosted Directus database, what needs rework, and how to plan the cutover and the license review.

On this page

Migrate from Sanity to Directus: what the move involves

The move from Sanity to Directus is a data model translation plus an export, not a file copy. Sanity's document types, fields and references live in Studio schemas in code, while Directus stores content in tables you define in your own SQL database, so each document type becomes a collection, each reference becomes a relation, and each record is rewritten to fit that structure. Start by running the sanity dataset export command to produce the gzipped tarball, then unpack it and read the NDJSON documents to inventory every type, field and reference before any Directus schema is created. Confirm with your Sanity project which datasets, drafts and history you need to keep, because the export carries document history but your Directus target only holds what you load into it.

Internal platform engineers usually own this work, with an implementation partner helping on the mapping rules, the Portable Text conversion and the cutover plan. The mapping and conversion tasks are the bulk of the effort: Portable Text blocks must be converted to a format your Directus front end can render, asset references must be re-uploaded into Directus file storage, and the export's skipped assets (those returning 401, 403 or 404 responses) need a written list so editors can supply replacements. Effort rises with the number of document types, the depth of nested objects, the volume of custom Studio input components and the amount of history you choose to preserve. Ask any partner for a fixed-scope written plan that names the mapping rules, test datasets and cutover steps before work starts.

Directus is not under an OSI open source license. It uses the Monospace Sustainable Core License, which permits internal use but restricts a Competing Use against Monospace's paid offerings, and each release converts to GPL-3.0 four years after release. Have legal review the license against your planned use, including whether you will offer Directus-based services to customers or other companies, before you commit to the migration. Also confirm which Directus release you will pin, since the Directus license text governs the terms that apply to each version you run.

Which Sanity capabilities map to Directus, and where rework is needed

This table compares how Sanity's content modeling, editing and storage features map to Directus collections, relations, Studio, file storage and permissions. Read each row as clean, needs rework or gap, and treat every gap as a item to confirm in your own environment before you commit to a migration plan.

CapabilitySanityDirectus and what to confirm
Document typesCode-defined schemas in Studio, each document type stored as JSON documents in Content LakeNeeds rework: each type becomes a Directus collection with fields you define in the database or Studio, so schema code must be rewritten
ReferencesTyped references between documents, resolved in GROQ queriesNeeds rework: map to many-to-one and many-to-many relations in SQL, then confirm that your reference depth matches what Directus returns through its APIs
Portable TextStructured rich text stored as block arrays with custom marks and embedded objectsNeeds rework: convert blocks to HTML, Markdown or a JSON field your front end can parse, and test every custom block type
AssetsAssets stored in Sanity's asset pipeline with image transformations via URL parametersNeeds rework: re-upload files to Directus file storage or your own object storage, then confirm how image transformations are provided in your setup
Drafts and version historyDocument history is included in the dataset export, and drafts are a Studio conceptGap to confirm: Directus has no built-in equivalent of Content Lake document history for all content; confirm whether revisions and history retention meet your audit needs
Real-time collaborationMultiple editors see live changes through Content LakeGap to confirm: Directus Studio does not match Sanity's real-time co-editing; test concurrent editing with your editors before cutover
Role-based accessRoles and dataset-level and document-level access controlled in SanityNeeds rework: Directus permissions are defined per role and collection; rebuild each rule and test it against the native MCP server and API users
Editing experienceStudio is code-defined, extensible in React, and deployed by youNeeds rework: Directus Studio is database-defined and generated from the schema, so custom Sanity input components must be replaced with Directus extensions or standard fields

How the Sanity dataset export tarball is unpacked

The `sanity dataset export` command writes your dataset to a local gzipped tarball, and that archive is the only copy of your content you hold before the migration starts. According to Sanity's CLI reference, the export includes document history and asset files, which means the archive carries more than the current published state. Run the command with the Sanity CLI version your team uses today, and confirm the flags for asset handling and history in your own environment before you rely on the output, because flag names and defaults can change between CLI releases. Store the tarball somewhere versioned and read-only so every later mapping step can be rerun against the same input.

Once you extract the archive, the document records sit in an NDJSON file, one JSON object per line, while binary assets are stored as separate files alongside it. Separate the two groups before you write any Directus import logic. Document records become rows in your SQL tables, and each asset file needs a matching entry in Directus's file storage, so keep a manifest that links each asset file to the document fields that reference it. Read the NDJSON in a streaming parser rather than loading it whole, and count the records by _type so you can check the totals against the source dataset later.

The export skips any asset that returns a 401, 403 or 404 response, so the archive can be incomplete in ways that do not show up as an error. Compare the asset references found in the documents with the files actually present in the archive, and list every missing asset. Then reconcile that list against your own asset inventory, such as the original upload source, your CDN logs or the people who uploaded the files, and decide whether each gap needs re-uploading from source or a documented exception for editors. Treat this reconciliation as a required migration step, because a missing image discovered after cutover is much harder to trace.

Which data and integrations move, and which must be rebuilt

Most of a Sanity dataset maps cleanly to Directus once the document types are turned into SQL tables. The parts that need engineering time are the rich text conversion, the Studio customizations, and every system that reads from or writes to Sanity today. Confirm each of these before you set a cutover date.

Document types become SQL tables

Each Sanity document type becomes a table in your SQL database, and Directus reads that schema directly rather than storing its own content model. Field types such as strings, numbers, booleans and dates map to native columns, while nested objects and arrays need a decision about whether they become related tables or JSON fields. Check how draft and published versions appear in the exported NDJSON, because Directus has no built-in equivalent of Content Lake document IDs.

References become relations

Sanity references between documents, such as an article pointing to an author, need to become foreign keys or many-to-many junction tables in Directus. Orphaned references in the export, where a referenced document was deleted, will break the import unless you clean them up first. Test one document type end to end before running the full load.

Portable Text becomes a structured field

Portable Text is Sanity's JSON block format for rich text, and it does not map to HTML or Markdown without a converter. Decide whether to store the blocks as a JSON field, render them to HTML at build time, or split them into separate fields for each content block. Editors will notice formatting loss first, so sample real articles with embedded images, custom marks and annotations before you commit to a conversion approach.

Asset files move to Directus storage

The dataset export includes asset files, but the export command skips any asset that returns 401, 403 or 404, so those files need a separate review. Upload the retained files into Directus file storage and rewrite every stored asset reference to point at the new file IDs. Confirm where Directus will store files (local disk or an object storage bucket you control) and whether image transformations are configured before the first load.

Studio customizations must be rebuilt

Custom input components, document actions, validation rules and desk structure in Sanity Studio do not carry over to Directus. Directus Studio covers standard collection and field setup, so list each customization in your current Studio code and decide whether it is replaced by a Directus field setting, an extension, or dropped. Ask your team to confirm which editor workflows must survive the move before anyone starts the rebuild.

Webhooks and front-end queries are repointed

Sanity GROQ queries in your front ends and the webhooks that trigger builds or cache purges must be rewritten against the REST or GraphQL APIs that Directus generates from the database schema. Confirm which permissions and roles the API tokens need, since Directus applies role-based access to every request and the team must recreate those rules by hand. Also verify which integrations exist outside your own code, such as third-party plugins, and whether each has a Directus equivalent.

The migration sequence from inventory to decommission

This sequence moves a Sanity dataset into Directus in five gated steps, starting with a license review and an inventory so every later step works from a known scope. Each step produces a named artifact, and the Sanity dataset is retired only after outputs have been verified side by side.

  1. Review the license and inventory the dataset

    Start with the license review, not at the end of the project. Have legal or procurement check the Monospace Sustainable Core License 1.0 against your planned use of Directus, including whether any internal, client-facing or resold use would count as a Competing Use against Monospace's paid offerings. In parallel, inventory every document type, the dataset's document count and history scope, referenced assets, GROQ queries, webhooks, Studio customizations and downstream consumers such as front ends and search indexes. Done means a signed-off license position and a written inventory that the team agrees is complete.

  2. Export the dataset and unpack the tarball

    Run the Sanity dataset export to produce the local gzipped tarball, which includes document history and asset files. Record which assets were skipped because the export returned 401, 403 or 404 responses, since those gaps must be resolved before cutover. Unpack the tarball into a working directory, keep an untouched archive copy for audit, and confirm the document counts match the inventory. Done means a versioned, checksummed export and a list of skipped assets with owners assigned.

  3. Map schemas and pilot one document type

    Translate one representative document type into a Directus collection, with fields, relations and roles defined in the Directus database schema. Convert its references into foreign keys or junction tables, and convert a sample of Portable Text into the format your front end expects. Load a copy of the export into a non-production Directus instance backed by PostgreSQL or another supported database, then query the result directly in SQL. Done means one document type renders correctly in the consuming front end, and the team has a written mapping rule set for the rest.

  4. Load the full dataset and re-upload assets

    Apply the mapping rules to all document types, load documents in dependency order so references resolve, and re-upload asset files to your own storage, updating each record to point at the new location. Rewrite any stored asset URLs in content and rebuild the skipped assets from their owners where possible. Reproduce the GROQ queries used by the front end as REST or GraphQL calls against the generated APIs. Done means a loaded environment with zero unresolved references and a list of assets still outstanding.

  5. Run Sanity and Directus in parallel

    Keep Sanity as the editing source while a Directus instance serves a copy of the front end or API responses. Compare rendered pages, API payloads, search results and permission behavior for the same content, and test editor workflows in Directus Studio with roles that mirror the Sanity access model. Track each difference to a fix or an accepted exception. Done means a sign-off record showing the agreed comparison set matches, with every exception documented and approved.

  6. Cut over with a documented rollback plan

    Freeze edits in Sanity for the cutover window, run a final export and incremental load, switch the front end and integrations to Directus, and confirm webhooks, scheduled publishing and permissions behave as expected. Write the rollback plan before the switch: the conditions that trigger it, the steps to point consumers back to Sanity, and how edits made in Directus during a rollback would be reconciled. Done means production traffic is served from Directus and the rollback procedure has been rehearsed.

  7. Decommission the Sanity dataset after retention

    Keep the Sanity dataset and final export for the retention period your records, legal and compliance owners set, so you can answer questions about historical content. Remove integrations and API tokens pointing at Sanity, and confirm no consumer still reads from it. Store the final export according to your data retention policy, then delete the hosted dataset and record the decommission date. Done means a closed decommission ticket, revoked credentials and an archived export with its checksum.

Reviewing the MSCL license against how you will use Directus

Directus is licensed under the Monospace Sustainable Core License 1.0 (MSCL-1.0-GPL), which permits any use except a Competing Use against Monospace's paid offerings. Running Directus to manage your own website content, product data and internal back-office records is not a Competing Use, so this pattern is the least likely to raise license questions. The license is not OSI open source, so it should not be described internally as open source without a legal check.

  • Your own content: Editors, developers and integrations inside your organization use Directus to serve your own sites and apps.
  • Internal tools: Staff use Studio for operational data that never becomes a product sold to others.
  • Self-hosting: Running Directus with Docker in your own cloud account or data center is the deployment model the license is built around.
  • Version tracking: Each release converts to GPL-3.0 four years after its release date, so older versions carry different terms over time.
  • Documentation: Keep the license file version you deployed in your architecture records.

Confirm with counsel that your internal use, including any affiliates or contractors who operate the system, fits the license text as published.

What drives the cost and duration of the move

This table lists the factors that change the effort of moving a Sanity dataset into Directus, why each one matters, and how to reduce it. Read it before requesting a quote, since the one-time migration work and the recurring hosting and upkeep costs respond to different drivers. Most of the cost sits in mapping and cutover, so scope those explicitly in the written quote.

DriverWhy it mattersHow to keep it down
Document types and referencesEach document type becomes a Directus collection with its own fields, and each reference becomes a relation. Deep reference chains multiply mapping and test work.Inventory every document type and reference from the Studio schema before scoping. Retire unused types and flatten references that no longer serve editors.
Portable Text complexity and custom marksPortable Text blocks, inline objects and custom marks must be converted into a format Directus stores and renders. Custom marks and nested block types need bespoke converters.Audit the block types actually used in content. Limit custom marks, and agree the target format (for example, Markdown or structured JSON) with your front-end team early.
Asset volume and skipped assetsRe-uploading assets takes time roughly in line with file count and size. The export skips assets that return 401, 403 or 404 responses, so some files may be missing from the tarball.Ask the vendor for a count of assets in the export and a list of skipped files. Decide in advance how missing assets are handled, and budget a separate pass to recover or replace them.
Studio customizations and front-end rewiringCustom input components, validation logic and document actions in Sanity Studio have no direct equivalent in Directus. Front-end queries against GROQ must be rewritten to REST or GraphQL.List every custom Studio plugin and every GROQ query used by the site. Keep editor workflows simple in Directus Studio and move business logic into the database or the front end.
History and draft fidelityThe export includes document history, but Directus does not replay Sanity revisions. Drafts and in-flight edits may need a decision about what is migrated.Decide whether editors need historical versions or only current published content. Migrate published content first, then add drafts only where editors need them.
Parallel-run lengthRunning Sanity and Directus side by side keeps both systems in sync for editors and developers and adds cost for each day both are live. Longer runs need a sync or re-export step.Set a short, written cutover window with a freeze on Sanity editing. Agree the number of re-exports and the sync method before work starts.
License reviewDirectus uses the Monospace Sustainable Core License, which is not OSI open source. Its terms bar a Competing Use against Monospace's paid offerings. Legal review adds time before go-live.Have counsel confirm the license against your intended use, such as internal use or a customer-facing product, before signing a scope. Check the license file and directus.com/license.
One-time work (mapping, scripts, cutover)Schema mapping, migration scripts, asset re-upload, testing and cutover are paid once but often make up the largest share of the first project.Ask the quote to split these tasks into separate line items with written acceptance criteria.
Recurring work (hosting, backups, upgrades)Database hosting, storage, backups, Directus upgrades and security patches continue after launch and scale with content volume and traffic.Ask for estimated monthly infrastructure needs, the backup schedule and the upgrade and support model in writing, and compare them with the current Sanity plan.

Questions buyers ask before moving from Sanity to Directus

How much effort does a move from Sanity to Directus take?

The effort depends mostly on how many document types you have, how deeply they reference each other, and how much rich text and media sits in the dataset. Each document type becomes a SQL table with relations, so a schema with many cross-references needs more mapping decisions than a flat one. Portable Text needs a conversion step into the block structure your front end expects, and every asset must be re-uploaded to storage you control. Ask for a written inventory of document types, reference fields, custom input components and asset counts before agreeing on scope, since those numbers set most of the work.

How long does a Sanity to Directus migration take?

The timeline is set by the number of content types, the volume of assets, the number of front-end consumers that read the Sanity API, and how much validation editors need before cutover. A dataset with a small schema and few assets moves faster than one with years of content and many custom Studio plugins. Plan for a parallel period where the old and new systems both run, so editors can check content and developers can switch API calls. Confirm the phases, acceptance criteria and dates with your implementation partner in the written scope rather than relying on a general estimate.

What does our team need to provide during the migration?

Your team needs to supply access to the Sanity project and dataset, the Studio schema source code, and a list of which front-end applications and integrations read content. Editors should name the content they rely on most and help define what a correct migrated entry looks like. Engineers will need to decide how Directus roles and permissions map to your editorial workflow, and who owns the new database and object storage after go-live. Sanity's export command skips assets that return 401, 403 or 404 responses, so someone on your side must check the asset gaps report and resolve them.

Can an internal team complete the Sanity to Directus move alone?

An internal team can complete the move if it has people who know SQL schema design, the Sanity export format, and how your front end consumes content. The main risks are unmapped references, Portable Text edge cases, and asset paths that break after re-upload. Directus connects to an existing SQL database through the DB_CLIENT setting and supports PostgreSQL, MySQL, MariaDB and others, so the database engineering choices are yours to make. Many teams split the work: internal staff own the content model and cutover, while an outside partner handles the converter scripts, hardening and documentation. A fixed-scope agreement can define which part you keep in-house.

Do document history and drafts carry over to Directus?

Not automatically. Sanity's dataset export includes document history and asset files in a gzipped tarball, but Directus stores content in your SQL tables and does not read that history format on its own. Migrated content typically arrives as current versions, and any history you want to keep needs a deliberate mapping, such as a revisions table or an archive you query separately. Drafts need the same decision: decide whether unpublished work is migrated, paused, or re-entered by editors. Ask the implementation partner to state in writing which history, drafts and versions are carried over and where the rest is archived.

Does the Monospace Sustainable Core License allow our planned use of Directus?

The Monospace Sustainable Core License permits internal use, but it bars a Competing Use against Monospace's paid offerings. If you run Directus to power your own websites, apps and internal tools, that is generally internal use, but a product that offers Directus-based hosting or content services to third parties may fall into the restricted category. The license also converts each version to GPL-3.0 four years after release, and Directus is not under an OSI open source license, so the terms differ from the GPL-based CMSs you may be comparing. Have your legal team read the directus.com license page and the repository license file against your exact plans, and confirm the terms with Directus before committing.

What usually goes wrong in a Sanity to Directus move

Most failed Sanity to Directus moves break in the same few places: the export, the data model, the rich text, and the cutover. Each risk below is one a team can prevent with a specific check before editors and front ends depend on the new system.

Skipped assets go unreconciled

The Sanity dataset export skips asset files that return 401, 403 or 404 responses, so the tarball can look complete while images and files are missing. Compare the asset references in exported documents against the files actually present, and log every skipped asset. Decide per asset whether to re-upload from a source copy, replace it, or remove the reference before cutover.

Portable Text loses marks and blocks

Portable Text stores rich text as structured JSON, and custom blocks, annotations and inline objects have no automatic equivalent in a Directus field. Text can survive while bold, links or embedded components disappear. Run a sample of complex articles through the conversion and compare rendered output with the original before accepting the mapping.

References break when IDs change

Sanity references point to document _id values, and those values often differ once rows are re-created as SQL records with new primary keys. Keep the original _id as a stored column, build a lookup table during import, and rewrite every relation in a second pass. Then check that no foreign key is empty for required fields.

Front ends query old shapes

Directus generates REST and GraphQL endpoints from the database schema, so field names and nesting that the front end expects from GROQ queries may no longer match. Teams often update the schema and forget the consuming code, or leave draft and published states unmapped. Inventory every query the site uses, then test each one against the Directus endpoints in staging.

License assumptions without legal review

Directus uses the Monospace Sustainable Core License rather than an OSI open source license, and that license bars competing use against Monospace's paid offerings. Whether an internal editorial platform or a customer-facing product built on Directus falls within the permitted uses depends on your business. Have counsel review the license file against your actual deployment, and record the decision before you commit.

Cutover without a rollback path

Editors keep writing to Sanity until the switch, so a final delta export is needed, and a cutover without a tested rollback leaves content split across two systems. Rehearse the full import and delta sync on a copy, define the freeze window, and keep the Sanity dataset readable until the new site has run cleanly for an agreed period.

How the move differs by starting point

A small team with a handful of document types usually has a schema that fits in one afternoon of review. The mapping is straightforward: each document type becomes a Directus collection, each field becomes a column or a relation, and references become foreign keys. Because Directus sits on a plain SQL database, a small project can often be rebuilt by one or two people who already know the Studio schema. The main risk is treating the export as final before editors confirm what they actually use.

  • Schema review: List every document type in your Studio schema and note which ones editors still create. Retire unused types instead of migrating them.
  • Reference shape: Count the cross-document references. Few references mean simple foreign keys and little relation design.
  • Parallel run: A short freeze of editing, followed by a single import from the NDJSON documents, is often enough for a low-volume site. Confirm the editor freeze window with your content owners.
  • Assets: Re-upload the files from the tarball into Directus file storage and check the skipped-asset report from the export.
  • Rebuild scope: Your front end still needs its queries rewritten against the Directus REST or GraphQL APIs.

Before you commit, ask the team to walk through a sample of published pages in both systems and confirm that the content matches.",

How DeployOpen scopes and runs the migration

The sequence below takes a Sanity dataset from an exported tarball to a Directus instance in your own infrastructure, with each stage closed by a written check. Scope and price are agreed in writing before any engineering starts.

  1. Agree the written scope first

    DeployOpen reviews the Sanity project, its datasets, document types, expected content volume, editor roles and target hosting with your team, then writes the scope, deliverables and timeline into an agreed statement of work. DeployOpen does not publish a price list, so a quote follows from that written scope. Nothing is changed in the Sanity project during this step. It is done when your sign-off on the scope document is recorded.

  2. Inventory the dataset and assets

    The team runs the Sanity dataset export to produce the gzipped tarball with documents, history and asset files. DeployOpen then lists every document type, reference field, Portable Text field and asset, and records which assets the export skipped on 401, 403 or 404 responses. The output is an inventory and a gap list that your content owners must confirm before any mapping begins.

  3. Design the SQL schema and relations

    DeployOpen maps each Sanity document type to a Directus-managed SQL table, converts references into relations, and decides how draft and published states, locales and singleton documents are represented. Your database team reviews the design against your own query and reporting needs. It is complete when the schema map is signed off and the target database engine, chosen from the engines Directus supports through its DB_CLIENT setting, is confirmed.

  4. Convert Portable Text and load content

    DeployOpen writes repeatable scripts that convert Portable Text blocks, marks and custom object types into the field format you choose for Directus, then load the NDJSON documents into the staging database. Scripts run against a copy of the export, never the live Sanity dataset. The check is a record-count and sample-field comparison per content type, reviewed by editors.

  5. Re-upload assets and rewrite links

    Asset files from the tarball are uploaded to your chosen storage, and DeployOpen rewrites image and file references in content so they point to the new locations. Any assets skipped during export are handled from a list your team has approved, either restored from another source or accepted as missing. The step closes when a rendered sample of pages shows no broken media references.

  6. Deploy, harden and document the instance

    DeployOpen installs Directus with Docker or on your own infrastructure, configures roles and permissions to match your editorial model, sets up backups and access controls, and writes the runbook for operations. Hardening follows the checklist agreed in the scope. Completion means a hardened staging environment, a tested restore from backup, and a documented runbook accepted by your operations lead.

  7. Run parallel review and cutover

    Editors and developers test content, previews, front-end builds and API consumers against Directus while Sanity remains the source of record. DeployOpen then plans the final export and load, the DNS or configuration switch, and a rollback path. Cutover is complete when the agreed acceptance tests pass and your team confirms the owner of the live system.

  8. Continue support under a retainer

    After cutover, DeployOpen can provide ongoing support, upgrades and continuous testing under a retainer, or hand the system to your team with the documentation. Directus upgrades, the MSCL license terms and your own compliance evidence are reviewed on the schedule set in that agreement. DeployOpen prepares controls and evidence for compliance assessments but does not issue audit reports or certifications, which independent auditors provide.

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.