portable-text-conversion
sanity-io/agent-toolkit
Convert HTML and Markdown into Portable Text blocks for Sanity content migration and pipelines.
What is portable-text-conversion?
Transforms external rich-text content (HTML, Markdown) into Sanity's Portable Text format for content ingestion and migration. Use this when importing from legacy CMSs, building content pipelines, or programmatically creating Portable Text documents.
- Convert Markdown to Portable Text using @portabletext/markdown
- Parse HTML into Portable Text blocks using @portabletext/block-tools
- Manually construct Portable Text blocks from any data source
- Handle text styling, marks, annotations, and list structures
- Support custom block types and nested content
- Generate unique keys and maintain Portable Text specification compliance
How to install portable-text-conversion
npx skills add https://github.com/sanity-io/agent-toolkit --skill portable-text-conversion- Sanity project setup
- Node.js environment
- Understanding of Portable Text structure and blocks
How to use portable-text-conversion
- 1.Choose your source format: Markdown, HTML, or manual construction
- 2.For Markdown: use markdownToPortableText from @portabletext/markdown
- 3.For HTML: use htmlToBlocks from @portabletext/block-tools
- 4.For custom sources: manually construct blocks following the Portable Text specification
- 5.Ensure all blocks and spans have unique _key values
- 6.Map source content to appropriate Portable Text block types (block, image, custom types)
- 7.Handle marks and markDefs for text annotations
- 8.Test conversion output against Portable Text schema before importing
Use cases
- Migrating content from legacy CMS platforms to Sanity
- Importing HTML or Markdown files into Sanity projects
- Building automated content pipelines that ingest external sources
- Converting rich-text formats between different systems
- Programmatically generating Portable Text documents from APIs or databases
- Content migration specialists
- Backend developers building content pipelines
- Sanity CMS administrators
- Full-stack developers integrating external content sources
portable-text-conversion FAQ
@portabletext/block-tools is the current package; @sanity/block-tools is legacy. Use @portabletext/block-tools for new projects—the API is identical.
Yes, every block and span requires a unique _key within the array. This is essential for Sanity's content tracking and editing.
Yes, htmlToBlocks handles nested structures, but custom deserializers may be needed for non-standard HTML or deeply nested content.
Use manual construction to build Portable Text blocks programmatically from any data source (APIs, databases, custom formats).
Include image blocks with asset references, or use custom block types. Map source media to Sanity asset references during conversion.
Full instructions (SKILL.md)
Source of truth, from sanity-io/agent-toolkit.
name: portable-text-conversion description: Convert HTML and Markdown content into Portable Text blocks for Sanity. Use when migrating content from legacy CMSs, importing HTML or Markdown into Sanity, building content pipelines that ingest external content, converting rich text between formats, or programmatically creating Portable Text documents. Covers @portabletext/markdown (markdownToPortableText), @portabletext/block-tools (htmlToBlocks), custom deserializers, and the Portable Text specification for manual block construction. license: MIT metadata: author: sanity version: "1.0.0"
Portable Text Conversion
Convert external content (HTML, Markdown) into Portable Text for Sanity. Three main approaches:
markdownToPortableText— Convert Markdown directly using@portabletext/markdown(recommended for Markdown)htmlToBlocks— Parse HTML into PT blocks using@portabletext/block-tools(for HTML migration)- Manual construction — Build PT blocks directly from any source (APIs, databases, etc.)
Portable Text Specification
Understand the target format before converting. PT is an array of blocks:
[
{
"_type": "block",
"_key": "abc123",
"style": "normal",
"children": [
{"_type": "span", "_key": "def456", "text": "Hello ", "marks": []},
{"_type": "span", "_key": "ghi789", "text": "world", "marks": ["strong"]}
],
"markDefs": []
},
{
"_type": "block",
"_key": "jkl012",
"style": "h2",
"children": [
{"_type": "span", "_key": "mno345", "text": "A heading", "marks": []}
],
"markDefs": []
},
{
"_type": "image",
"_key": "pqr678",
"asset": {"_type": "reference", "_ref": "image-abc-200x200-png"}
}
]
Key rules:
- Every block and span needs
_key(unique within the array) _type: "block"is for text blocks; custom types use their own_typemarkDefsholds annotation data;markson spans referencemarkDefs[*]._keyor are decorator strings- Lists use
listItem("bullet" | "number") andlevel(1, 2, 3...) on regular blocks
Conversion Rules
Read the rule file matching your source format:
- Markdown → Portable Text:
rules/markdown-to-pt.md—@portabletext/markdownwithmarkdownToPortableText(recommended) - HTML → Portable Text:
rules/html-to-pt.md—@portabletext/block-toolswithhtmlToBlocks - Manual PT Construction:
rules/manual-construction.md— build blocks programmatically from any source
Note:
@sanity/block-toolsis the legacy package name. Always use@portabletext/block-toolsfor new projects. The API is the same.
Related skills
More from sanity-io/agent-toolkit and the wider catalog.

portable-text-serialization
Render and serialize Portable Text across React, Vue, Svelte, Astro, HTML, Markdown, and plain text.

sanity-best-practices
Sanity development best practices for schema design, GROQ, TypeGen, Visual Editing, and framework integrations.

sanity-migration
Plan, implement, and validate CMS-to-Sanity migrations with structured ETL workflows.

seo-aeo-best-practices
SEO and AEO best practices for metadata, structured data, sitemaps, and AI answer engine optimization.

book-study
Systematic reading coach with knowledge compilation, mastery testing, and spaced repetition for deep book learning.

code-review-expert
Expert code review of git changes detecting SOLID violations, security risks, and proposing actionable improvements.