Let me tell you about the worst hour of my Tuesday.
I wrote a 2,000-word blog post in Notion. Beautiful formatting, perfect headings, code blocks, the works. Then I tried to publish it to my Sanity CMS.
One hour later, I was manually converting this:
## How to Use the API
Simply call the `fetchData()` function:
\`\`\`javascript
const data = await fetchData()
\`\`\`
Into this monstrosity:
{
_type: 'block',
style: 'h2',
children: [{ _type: 'span', text: 'How to Use the API' }]
},
{
_type: 'block',
children: [
{ _type: 'span', text: 'Simply call the ' },
{ _type: 'span', text: 'fetchData()', marks: ['code'] },
{ _type: 'span', text: ' function:' }
]
},
{
_type: 'code',
language: 'javascript',
code: 'const data = await fetchData()'
}
I literally said out loud: "There has to be a better way."
Turns out, there is.
Why Portable Text Makes You Want to Scream
Don't get me wrong - Sanity is fantastic. The headless CMS architecture is brilliant, the API is clean, and the real-time collaboration is π₯.
But Portable Text? It's like they said:
"You know what developers love? Converting their perfectly good Markdown into deeply nested JSON objects by hand."
Nobody. Nobody said that.
The problem is that Portable Text is structured content. It's designed to be platform-agnostic, queryable, and transformable. Which is great! Until you actually have to write content in it.
The Solution: Markdown Plugin
Here's the good news: Sanity has a markdown plugin. Here's the bad news: nobody talks about it.
Let me show you exactly how to set it up in your Sanity project.
Step 1: Install the Plugin
cd your-sanity-studio
# Install the markdown plugin
npm install sanity-plugin-markdown easymde@2
That's it for installation. Now for configuration.
Step 2: Update Your Sanity Config
Open your sanity.config.ts
and add the markdown schema to your plugins:
import { defineConfig } from 'sanity'
import { structureTool } from 'sanity/structure'
import { markdownSchema } from 'sanity-plugin-markdown'
export default defineConfig({
name: 'default',
title: 'Your Project',
projectId: 'your-project-id',
dataset: 'production',
plugins: [
structureTool(),
markdownSchema(), // π Add this line
],
schema: {
types: [...yourSchemas],
},
})
Step 3: Add Markdown Field to Your Schema
Now update your post schema to include a markdown content field:
import { defineField, defineType } from 'sanity'
export const postType = defineType({
name: 'post',
title: 'Post',
type: 'document',
fields: [
defineField({
name: 'title',
type: 'string',
validation: (rule) => rule.required(),
}),
defineField({
name: 'slug',
type: 'slug',
options: { source: 'title' },
}),
// π― The magic field
defineField({
name: 'content',
title: 'Content',
type: 'markdown',
description: 'Write your content in beautiful Markdown',
}),
],
})
Step 4: Style the Editor (Optional but Recommended)
The default markdown editor is... functional. Let's make it nice:
# Install CSS dependencies
npm install easymde@2
Create sanity.css
in your studio root:
@import 'easymde/dist/easymde.min.css';
/* Make it look less like 2010 */
.EasyMDEContainer .CodeMirror {
border-radius: 8px;
border-color: #e2e8f0;
font-family: 'JetBrains Mono', 'Fira Code', monospace;
font-size: 14px;
line-height: 1.6;
}
.EasyMDEContainer .editor-toolbar {
border-color: #e2e8f0;
border-radius: 8px 8px 0 0;
background: #f8fafc;
}
.EasyMDEContainer .editor-toolbar button {
color: #475569;
}
.EasyMDEContainer .editor-toolbar button:hover {
background: #e2e8f0;
border-color: #cbd5e1;
}
Import it in your studio's main file.
What You Get
After this setup, your Sanity Studio has a proper markdown editor with:
β
Live preview side-by-side
β
Toolbar for formatting (no more memorizing markdown syntax)
β
Code block support with syntax highlighting
β
Image insertion
β
Table support
β
Full keyboard shortcuts
And here's the best part: it stores actual markdown text, not Portable Text JSON.
Rendering Markdown on Your Frontend
Now when you query your Sanity content, you get clean markdown strings:
// What you get from Sanity
const post = {
title: "My Post",
content: "## Introduction\n\nThis is **markdown**!"
}
To render it in your Next.js/React app:
npm install react-markdown remark-gfm rehype-raw rehype-sanitize
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
export default function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
className="prose prose-lg"
>
{post.content}
</ReactMarkdown>
</article>
)
}
Boom. Clean, simple, no Portable Text serializers required.
Common Gotchas
Gotcha #1: "Unknown type: markdown"
If you see this error, you forgot to add markdownSchema()
to your plugins array in sanity.config.ts
.
Gotcha #2: Editor looks broken
Make sure you're importing the CSS. The easymde styles are required:
import 'easymde/dist/easymde.min.css'
Gotcha #3: Images not working
Markdown image syntax expects URLs:

If you want to use Sanity's image CDN, you'll need to either:
- Upload images separately and use the CDN URL
- Stick with Portable Text for the image field
- Use a mixed approach (markdown for content, separate image fields)
Why This Matters
Look, I get it. Portable Text is "the right way" to do structured content. But sometimes you just want to write a damn blog post without feeling like you're programming JSON.
Markdown gives you:
- Speed - Write content at the speed of thought
- Portability - Works everywhere, from GitHub to Notion
- Simplicity - Everyone knows markdown
- Less friction - Copy-paste actually works
Is it perfect? No. But it's a hell of a lot better than manually building nested block objects.
The Full Working Example
I've set up a demo repo with a complete working Sanity Studio using markdown:
# Clone the example
git clone https://github.com/yourusername/sanity-markdown-example
cd sanity-markdown-example
# Install and run
npm install
npm run dev
Schema included, styles configured, ready to customize.
But Wait - There's an Even Better Way
Here's where I drop the pitch.
If you're:
- Writing lots of blog content
- Managing multiple Sanity projects
- Doing content work for clients
- Tired of the content β CMS workflow
You might want to check out Terradium.
It's an AI-powered content platform I built that:
- Generates SEO-optimized content using multi-agent AI
- Automatically publishes to Sanity in markdown format
- Handles the entire workflow from research to publishing
Here's the workflow:
You: "Write 5 blog posts about Next.js 15 features"
β
Terradium AI:
β Researches keywords
β Generates outlines
β Writes full articles
β Optimizes for SEO
β Publishes to your Sanity project
β
You: Review and click publish (or let it auto-publish)
Time saved: ~5 hours per article
Cost: Transparent "electron" credits (~$0.50 per full article)
Result: Professional content in your Sanity CMS, ready to review
The free tier gives you 30 electrons (~5 full articles) to try it out. No credit card required.
Why I Built This
After manually creating hundreds of blog posts for clients, I realized:
- The research phase is 80% the same every time
- SEO optimization follows predictable patterns
- Markdown β Sanity conversion should be automated
- The "publish to CMS" step is pure busywork
So I automated all of it with AI agents.
Now I use Terradium to:
- Generate client blog content in bulk
- Create documentation faster
- Populate demo projects with real content
- Test Sanity schemas with actual articles
It integrates directly with your Sanity project (using the markdown setup we just configured!) and handles everything from keyword research to final publishing.
Try It Out
If you just spent an hour following this tutorial to set up markdown support, you're exactly the person who would benefit from Terradium.
π Try Terradium Free - 30 electrons included, no credit card
Use your newly configured Sanity + Markdown setup, connect your project credentials, and generate your first AI-powered blog post in ~10 minutes.
Wrapping Up
Whether you use the markdown plugin manually or automate it with Terradium, the key takeaway is:
You don't have to fight Portable Text.
Markdown is a perfectly valid option for Sanity CMS. It's faster to write, easier to migrate, and frankly, way more pleasant to work with.
Set it up once, and never manually convert content again.
Questions?
Drop them in the comments! I'm happy to help with:
- Sanity + markdown setup issues
- Frontend rendering questions
- Migration from Portable Text to markdown
- Terradium integration
And if you found this helpful, consider giving Terradium a try. The free tier is genuinely useful (I'm not just saying that - it's 10 full articles).
TL;DR: Sanity's Portable Text is pain. Install sanity-plugin-markdown
, add markdownSchema()
to your config, use type: 'markdown'
in your schema. Write content like a normal person. Or automate the whole thing with Terradium and never write manually again.
Happy coding! π
Top comments (0)