If you write Jira tickets in Markdown, you've probably hit the same problem I did: the moment you paste that text into Jira, the result is inconsistent.
Sometimes you get raw **bold**, # headers, and pipe tables. Sometimes Jira partially formats things. Tables and code blocks usually need manual cleanup.
I built md2jira to make that workflow predictable.
What is md2jira?
md2jira is a monorepo with three independent pieces that share the same conversion engine:
Web previewer (apps/web)
A live two-panel editor in the browser. Paste Markdown on the left, get Jira-ready output on the right — instantly, with no backend, no login, and no data sent anywhere.
Use this if: you want to convert Markdown to Jira format right now without installing anything.
Core package (md2jira-core)
A pure TypeScript library — zero browser or framework dependencies. It exports two functions:
-
convert(md)→ Jira Wiki Markup string (for Jira Server / Data Center) -
convertToAdf(md)→ ADF JSON object (for Jira Cloud)
Use this if: you want to integrate Markdown-to-Jira conversion into your own Node.js app, script, or VS Code extension.
CLI (md2jira-cli)
A command-line tool that wraps md2jira-core. Reads a Markdown file (or stdin) and writes Jira Wiki Markup to stdout or a file.
Use this if: you want to convert files from the terminal or integrate the conversion into a shell script or CI pipeline.
md2jira input.md # stdout
md2jira input.md -o output.txt # write to file
cat input.md | md2jira # pipe from stdin
The problem in practice
Here's the difference between pasting raw Markdown directly into Jira and running it through md2jira first:
On the left, Jira gets raw Markdown and leaves it as plain text. On the right, the same content is converted into properly formatted Jira content with headings, emphasis, tables, nested lists, blockquotes, and code blocks.
The web previewer
The web app is designed for people who don't want to install anything. Go to the URL, paste your Markdown, copy the output.
The interface is a split panel:
- Left panel: a Markdown editor with line numbers, keyboard shortcuts (Ctrl+B, Ctrl+I, Ctrl+Shift+K, Alt+↑↓…), import/export, and a "Copy MD" button
- Right panel: live output with two independent toggles — format (Jira Cloud / Wiki Markup) and view (Preview / Code)
The "Copy for Jira" button is worth highlighting: it writes rich HTML plus plain text to the clipboard at the same time. When you paste directly into Jira Cloud, it renders as formatted content immediately — no manual cleanup needed. This is the main quality-of-life improvement over copying raw text.
What it converts
The core package currently handles:
-
# Heading→h1. Heading -
**bold**→*bold* -
_italic_→_italic_ -
~~strike~~→-strike- -
`inline code`→{{inline code}} - fenced code blocks →
{code}/{code:language=...} - unordered and ordered lists
- links, blockquotes, horizontal rules, and tables
Tables were the hardest part. They needed special handling for multiline cells, unequal column counts, escaping pipes inside cells, and inline formatting inside the table content itself.
What turned out to be harder than expected
At first glance, Markdown-to-Jira sounds like a simple string replacement problem. It isn't.
The hardest parts were:
- Tables: Jira table syntax is strict, and real Markdown tables are often messy
- Clipboard behavior: Jira Cloud reacts differently depending on whether the clipboard contains plain text or rich HTML
- ADF vs Wiki Markup: Jira Cloud prefers richer structured content, while Jira Server/Data Center workflows often still rely on Wiki Markup
-
Keeping the core reusable:
packages/corehad to stay free of React and browser APIs so it can be reused in a future CLI and VS Code extension
The npm packages
Both packages are published to npm independently:
# Core library — use in your own Node.js/TS projects
npm install md2jira-core
# CLI — convert files from the terminal
npm install -g md2jira-cli
md2jira-core is a pure TypeScript library with zero browser or framework dependencies — it works in Node.js, Deno, Bun, and VS Code extensions. md2jira-cli is a thin wrapper around it that adds file I/O and stdin/stdout support.
Basic usage
import { convert } from 'md2jira-core'
const jira = convert(`
# My Issue
Some **bold** text, _italic_, and ~~strikethrough~~.
| Field | Value |
|--------|-------------|
| Status | In Progress |
| Priority | **High** |
- Item 1
- Item 2
- Nested item
\`\`\`js
console.log("hello")
\`\`\`
> A blockquote
[Jira Docs](https://confluence.atlassian.com/jira)
`)
console.log(jira)
Output:
h1. My Issue
Some *bold* text, _italic_, and -strikethrough-.
|| Field || Value ||
| Status | In Progress |
| Priority | *High* |
* Item 1
* Item 2
** Nested item
{code:language=js}
console.log("hello")
{code}
bq. A blockquote
[Jira Docs|https://confluence.atlassian.com/jira]
ADF (Atlassian Document Format)
For Jira Cloud, you can also output ADF — the native JSON format that Jira Cloud uses internally:
import { convertToAdf } from 'md2jira-core'
const adf = convertToAdf(`# Hello **World**`)
console.log(JSON.stringify(adf, null, 2))
The web app uses this output to generate the preview and the rich clipboard content used by the "Copy for Jira" action, which is what makes paste into Jira Cloud behave much better than plain text.
How it's built
The conversion pipeline is:
Markdown string
→ remark-parse (AST)
→ transforms/ (visit each node type)
→ Jira Wiki Markup string
Each node type (heading, paragraph, table, list, etc.) has its own transform function in packages/core/src/transforms/. The table transform handles the most edge cases — multiline cells joined with <br>, missing cells padded with empty values, and inline formatting (bold, italic, links, code) inside cells.
The monorepo is structured so that packages/core is 100% framework-agnostic — powering the web app, the CLI (md2jira-cli), and a future VS Code extension.
Tech stack
| Layer | Technology |
|---|---|
| MD Parser |
remark-parse + unified
|
| AST types | @types/mdast |
| UI | React 18 + Vite + Tailwind CSS v4 |
| Testing | Vitest |
| Package manager | pnpm workspaces |
If you work with Jira regularly, give it a try — feedback and PRs are very welcome!


Top comments (0)