Open-source project
yuin/goldmark avatar
yuin/goldmark

yuin/goldmark v2: a Go Markdown parser that keeps the source, not just the HTML

:trophy: The Golden Swiss Army Knife for markdown processing. 100% CommonMark compliant, AST w/ CST, Extensible, Fast, CJK-friendly.

5,042 stars320 forksGoMIT

At a glance

What is it?
goldmark v2 is a CommonMark 0.31.2 compliant parser and renderer for Go that separates parsing from rendering, keeps CST information on every node, and lets you build an AST by hand. It is a breaking redesign of v1, so the main question for adopters is extension support.
Who is it for?
Adopt goldmark v2 if you are starting a Go project that needs to parse Markdown, build or inspect an AST, or render to something other than HTML, and you can accept the early v2 release state. Stay on v1 if your pipeline depends on third-party extensions that have not been ported, because the README says extensions must support v2.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem goldmark v2 targets: Markdown as data, not just as HTML input

goldmark's original design goals were narrow and stated plainly in the README: extensibility, performance ahead of a semantically perfect AST, and a focus on converting Markdown to HTML. That worked well enough that the library became, in the author's words, a major Markdown parser in the Go ecosystem. The v2 motivation section is honest about what that success exposed. People wanted semantic analysis of Markdown through the AST, and they wanted detailed position information for things like language servers. The README also points at a newer pressure: Markdown used as a lingua franca for AI, which increases both semantic analysis and Markdown generation, plus conversion to formats other than HTML.

The v1 architecture was not built for those jobs. It prioritized HTML output, and breaking changes were avoided for years because third-party extensions would stop working. The author describes more than seven years of accumulated technical debt and a Go language that has since gained generics. v2 is the decision to pay that debt at once rather than keep patching. If you only ever convert Markdown to HTML, this is largely background. If you want to walk a document, map a node back to a byte offset, or emit Markdown instead of HTML, v2 is aimed at you.

Parser and renderer are separate types, and every node carries a start position

The visible change in v2 is structural. Parsing and rendering are clearly separated, which the README says makes rendering to non-HTML formats easier. In the usage example, a parser is constructed with parser.New(), an HTML renderer with html.New(), and the two are wired together explicitly: p.Parse(source) returns a document, then r.Render(&buf, source, doc) writes output. The render call takes the original source bytes alongside the tree, which is how a renderer can reach back to source information.

That source information is the CST half of the design. Nodes keep the original text rather than only a decoded value. The README gives concrete cases: goldmark records whether a heading used ATX or Setext syntax, whether a link was written inside angle brackets, and it can tell you & me apart from you & me. Most Markdown libraries keep only the decoded value, so that distinction is lost. For an LSP server or a Markdown formatter, that is the difference between a tool that can round-trip a document and one that quietly rewrites it.

The third piece is programmatic AST construction. The second usage example builds a document with ast.N(ast.NewDocument(), ...), nesting a paragraph, an emphasis node, and a paragraph with a class attribute set through text.NewMultiLineValue. The README states that a constructed AST can be rendered to another format. So the same tree type serves both directions: parsed from source, or assembled in code. The parsing algorithm itself is unchanged from v1, which matters for anyone porting an extension: the README says the most complex parsing part can be used almost as it is.

Installing goldmark v2 and rendering your first document

The README gives one install command. The module path carries the v2 major version, and go.mod declares go 1.25, so the toolchain requirement is not incidental.

bash
$ go get github.com/yuin/goldmark/v2

The first real use is a parse and render round trip. This example comes from the README, including the CJK source string, and it checks the output rather than printing it. The expected result is a paragraph containing a strong element, with the Japanese text and the full-width punctuation left intact.

go
import (
    "bytes"
    "github.com/yuin/goldmark/v2/parser"
    "github.com/yuin/goldmark/v2/renderer/html"
)

source := []byte("こんにちは、 **世界** 。")

var buf bytes.Buffer
p := parser.New()
r := html.New()

doc := p.Parse(source)
if err := r.Render(&buf, source, doc); err != nil {
    panic(err)
}

If you want to build a tree in code instead of parsing one, the README shows ast.N with ast.NewDocument() and ast.NewParagraph(), and attributes attached through text.NewMultiLineValue. That path is worth trying early, because it is the clearest demonstration of what v2 changed: the tree is a first-class object you can construct, not only something a parser hands back.

There is also an online playground at yuin.github.io/goldmark/playground/v2/ for checking output without writing Go. The README notes it is built with WASM and is 5-10MB, so it is a convenience, not a lightweight page.

Where goldmark v2 is the wrong choice

The README is unusually direct about v2's status: it is still in the early stages of release, and if you use an extension that does not support v2, you should use v1. That sentence is the whole adoption decision. goldmark's value comes largely from its extension ecosystem, and v2 is a breaking release by design. The README states that third-party extensions must support v2, and that while the core parsing algorithm is unchanged, extensions have to be updated. If your Markdown pipeline is a stack of community extensions, moving to v2 means waiting for each one, and the README offers no compatibility shim.

A second boundary is what the library is not. v2 clearly separates parser and renderer to make non-HTML output easier, but the README presents HTML rendering as the worked example; other formats are something you implement. If you need a ready-made renderer for a specific target, this is a toolkit, not a product.

The maintenance policy is worth reading before you commit. The project maintains bug fixes, including security fixes, up to one major version prior to the latest major version. That is a clear promise, but it is bounded: it is a bug-fix policy, not a feature-backport policy, and it assumes you are tracking major versions deliberately. For a library that third parties build on, that is reasonable. For a team that wants to sit on v1 indefinitely and still receive fixes, the policy eventually stops covering them.

goldmark compared with a CommonMark parser that has no CST

The natural alternative is a CommonMark parser that produces an AST but discards source-level detail, which is what the README attributes to other Markdown libraries: they keep the decoded value only. The practical difference shows up the moment you need to write Markdown back out. With goldmark v2, the README says you can write a node back to Markdown without losing information, because the tree remembers whether a heading was ATX or Setext, whether a link used angle brackets, and whether an ampersand was literal or an entity. A decoded-value parser cannot reconstruct those choices, so a formatter built on it will normalize documents it was only asked to reformat.

That is a real trade-off rather than a strict win. Carrying CST data costs memory and implementation effort, and the README frames v1's original design as deliberately choosing performance over a semantically perfect AST. v2 moves toward semantics. If your only goal is fast Markdown to HTML, the extra information is overhead you pay for and never read, and v1's priorities may still fit better.

The second axis is language. The README notes that CommonMark is designed primarily with Western languages in mind and that many implementations assume English text. goldmark is CJK-friendly, and the repository carries a cjk_test.go alongside commonmark_test.go. For documents mixing Latin and CJK text, that is a testing claim you can inspect in the repository rather than take on faith.

Migrating from v1 to v2, and what the migration tooling assumes

The README does not document a manual migration path in detail. Instead it points at LLM-driven skills, and the repository has .agent-plugins/, .claude-plugin/, AGENTS.md and CLAUDE.md at the top level, so the migration tooling is part of the repository rather than an external service. The README gives the commands for Claude Code and Copilot CLI.

bash
/plugin marketplace add yuin/goldmark@v2
/plugin install migrate-goldmark-v1-to-v2@yuin-goldmark-v2

Once installed, two skills are available, one for extension projects and one for applications. The README states these skills create a migration plan and execute it to update your code. The README also says you can migrate manually, so the skills are a convenience, not a requirement, and the implementation lives in .agent-plugins if you want to read what they do before running them.

For ongoing work, the Makefile is the map of the project's own checks. make test runs the parser package tests under the goldmark_v1_attribute tag and then the root tests with coverage across the ast, extension, parser, renderer, html, text and util packages. make lint runs golangci-lint and gopls check. make fuzz runs go test -fuzz=FuzzDefault in the fuzz directory, which matches the README's claim that the project is tested with go test --fuzz. If you are evaluating whether to depend on this library, those targets tell you more about its engineering discipline than any summary will.

The licence is MIT, which is permissive and compatible with commercial use. That is a statement about the licence text, not legal advice, and if your organisation has specific obligations around attribution or dependency review, that is a question for your own counsel.

Editorial conclusion

Adopt goldmark v2 if you are starting a Go project that needs to parse Markdown, build or inspect an AST, or render to something other than HTML, and you can accept the early v2 release state. Stay on v1 if your pipeline depends on third-party extensions that have not been ported, because the README says extensions must support v2. Before writing code, check that every extension you need has a v2 release, and read the migration skill files in .agent-plugins to see what the automated v1 to v2 migration actually changes.

Frequently asked questions

What is yuin/goldmark?

It is a Markdown parser and renderer written in Go, described in its README as the Golden Swiss Army Knife for markdown processing, compliant with CommonMark 0.31.2. It builds an AST that also keeps CST information, separates parsing from rendering, and depends only on the standard library.

How do I install goldmark v2?

The README gives a single command, go get github.com/yuin/goldmark/v2. The module's go.mod declares go 1.25, so check your toolchain version before starting.

Should I use goldmark v1 or v2?

The README says v2 is still in the early stages of release and advises using v1 if you depend on an extension that does not support v2, since third-party extensions must be updated for v2. If your use case is semantic AST analysis, position information, or generating Markdown, v2 is the version built for that.

How does goldmark handle CJK text?

The README describes goldmark as CJK-friendly and notes that CommonMark is primarily designed with Western languages in mind, which many implementations assume. The repository includes a cjk_test.go file alongside the CommonMark test suite, and the README's own usage example parses and renders a Japanese sentence.

What does goldmark's CST support actually preserve?

According to the README, nodes keep original source information so a document can be written back to Markdown without losing detail. It records whether a heading used ATX or Setext syntax, whether a link was enclosed in angle brackets, and it distinguishes a literal ampersand from an entity, which libraries that keep only the decoded value cannot do.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. yuin/goldmark on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/yuin-goldmark.svg)](https://hysenlabs.com/projects/yuin-goldmark)