
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI hear you—the markdown migration process can definitely be tricky! You're actually on a good path, and there are multiple approaches depending on your content structure.
Markdown → HTML → Portable Text vs. Direct Markdown → Portable Text
Both approaches work, but here's what to consider:
Going the HTML route (what you're exploring):
@sanity/block-tools with the htmlToBlocks functionDirect markdown route:
remark@portabletext packages mostly work in reverse (Portable Text → other formats)My recommendation: Stick with the HTML approach you're exploring. Here's why:
@sanity/block-tools has proven utilities for HTML → Portable Text conversion<figure> or <img> tags and transform them into custom block typesmarked, remark-html, or similar), then use htmlToBlocksQuick implementation pattern:
import {htmlToBlocks} from '@sanity/block-tools'
import {JSDOM} from 'jsdom'
import {marked} from 'marked' // or your preferred markdown parser
// Convert markdown to HTML first
const html = marked(yourMarkdownContent)
// Then to Portable Text
const blocks = htmlToBlocks(html, blockContentType, {
parseHtml: html => new JSDOM(html).window.document
})Pro tips:
htmlToBlocks is synchronous, so you'll need to handle image uploads and asset references in a separate post-processing stepThe two-step process (markdown → HTML → Portable Text) gives you more control and better debugging when things don't convert perfectly. Good luck with your migration!
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store