If your n8n workflow produces or consumes Markdown — changelogs, AI-generated text, documentation, rich-text comments — the Markdown node handles bidirectional conversion without any external API calls. This guide covers both operations, the options that matter, common gotchas, and three copy-paste patterns with free JSON.
What the Markdown Node Does
The Markdown node converts content between two formats:
-
Markdown → HTML — renders
.mdcontent into<p>,<h1>,<ul>,<code>, and other HTML tags. Useful for sending Markdown as email body, inserting into a CMS, or rendering in a webhook response. - HTML → Markdown — strips HTML and produces clean Markdown. Useful for extracting readable content from scraped pages, converting CMS content for AI processing, or archiving.
Both operations run locally inside n8n — no API key, no rate limit, no cost per call.
Node Configuration
Markdown → HTML
| Field | What it does |
|---|---|
| Markdown | The input field containing Markdown text (expression or static) |
| Destination Key | Output field name for the rendered HTML (default: html) |
| Options → Flavor |
github (GFM — tables, task lists, strikethrough) or original (CommonMark). Default: github
|
| Options → Tables | Enable/disable table parsing (GFM only) |
| Options → Task Lists | Enable/disable - [ ] / - [x] task list rendering |
| Options → Strikethrough | Enable/disable ~~text~~ rendering |
| Options → Smart Punctuation | Convert "quotes" and -- dashes to typographic equivalents |
HTML → Markdown
| Field | What it does |
|---|---|
| HTML | The input field containing HTML |
| Destination Key | Output field name for the Markdown result (default: markdown) |
| Options → Bullet Marker |
- or * for unordered list items |
| Options → Code Block Style |
fenced (backticks) or indented
|
| Options → Heading Style |
atx (# Heading) or setext (underline-style) |
| Options → Horizontal Rule | Character to use for <hr> (default * * *) |
Common Gotchas
1. Input is a field name, not a value
The Markdown field expects an expression pointing to the field containing your text, not raw Markdown inline. Use {{ $json.body }}, not the Markdown text itself.
2. GFM tables require the Tables option enabled
If your Markdown contains pipe tables and they render as plain text, check that Flavor is set to github and Tables is enabled.
3. HTML → Markdown loses style attributes
Inline styles (style="color:red") are stripped during conversion. Only semantic HTML (<strong>, <em>, <h1>, etc.) maps cleanly to Markdown equivalents.
4. Code blocks with language hints
Markdown → HTML preserves `javascript fenced code blocks with a language-javascript class. Whether the HTML renderer highlights them depends on the consuming system.
5. Nested lists and complex HTML
Deeply nested lists and complex table HTML may not round-trip cleanly through HTML → Markdown. Spot-check the output if your source HTML is generated by a rich-text editor (Notion, Confluence, Quill).
6. Large documents and expression size limits
Very large Markdown documents (> 100KB) passed as expressions may hit n8n expression size limits. Use the Read/Write Files node to load large files as binary and convert them in a Code node instead.
Three Workflow Patterns
Pattern 1: AI Summary → HTML Email
Trigger: Schedule or webhook
OpenAI / Claude: Generate a Markdown summary of a report or dataset
Markdown node: Convert Markdown → HTML (Flavor = github, Tables = on)
Gmail / SMTP: Send the HTML as the email body (isBodyHtml: true)
AI models output clean Markdown naturally. This pattern converts that output into a properly formatted HTML email without manual formatting work.
`json
{
"name": "AI Summary to HTML Email",
"nodes": [
{"type": "n8n-nodes-base.scheduleTrigger", "name": "Daily 8am", "parameters": {}},
{"type": "@n8n/n8n-nodes-langchain.openAi", "name": "Summarize", "parameters": {"prompt": "Summarize today's metrics in Markdown with a table."}},
{"type": "n8n-nodes-base.markdown", "name": "To HTML", "parameters": {"mode": "markdownToHtml", "markdown": "={{ $json.text }}", "options": {"flavor": "github", "tables": true}}},
{"type": "n8n-nodes-base.gmail", "name": "Send Email", "parameters": {"subject": "Daily Summary", "message": "={{ $json.html }}", "isBodyHtml": true}}
]
}
`
Pattern 2: CMS Content → Markdown Archive
Trigger: Webhook (content update event from WordPress, Ghost, or Contentful)
HTTP Request: Fetch the full HTML post body
Markdown node: Convert HTML → Markdown (Heading Style = atx, Code Block = fenced)
Google Drive / Notion: Store the Markdown file for archiving or AI ingestion
This creates a clean, portable Markdown archive of every CMS post automatically on publish.
Pattern 3: GitHub README → Slack Rich Message
Trigger: Schedule or webhook
HTTP Request: Fetch a raw GitHub README.md
Markdown node: Convert Markdown → HTML
Slack: Post the HTML content as a Block Kit section (extract headings and first paragraph for a summary card)
Useful for syncing documentation updates to a Slack channel so teams see what changed without visiting GitHub.
Free Workflow JSON
Download a ready-to-import workflow covering all three patterns above:
👉 n8n Workflow Starter Pack — pirateprentice.gumroad.com/l/sxcoe
Import via n8n → Settings → Import Workflow. Credentials not included — wire your own after import.
Related Articles
- n8n HTML Node — generate HTML from templates in n8n
- n8n HTML Extract Node — scrape data from HTML with CSS selectors
- n8n Extract From File Node — parse file formats including HTML
- n8n Convert to File Node — export items as files
Are you using the Markdown node to render AI-generated content, convert CMS posts, or archive documentation? Drop your use case in the comments.
Top comments (1)
Are you using the Markdown node to convert AI output into HTML emails, archive CMS content as Markdown, or sync docs to Slack? Drop your use case below.