# Migrate Goldmark Extension V1 To V2

> Migrate goldmark extension from goldmark v1 to v2.

- Skill: `yuin/migrate-goldmark-extension-v1-to-v2` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add yuin/migrate-goldmark-extension-v1-to-v2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yuin/migrate-goldmark-extension-v1-to-v2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: yuin (https://skillmd.com/u/yuin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/yuin/migrate-goldmark-extension-v1-to-v2

---


# migrate-goldmark-extension-v1-to-v2
## Description
This skill helps you migrate a goldmark (https://github.com/yuin/goldmark) extension from version 1 to version 2. It
provides guidance on the changes needed to update your project to be compatible with the new version of goldmark.

## Knowledges

- [CommonMark key points](../../references/commonmark-key-points.md) : List of key points of CommonMark spec that you should be aware of when implementing a goldmark extension.
- [Breaking changes in v2](../../references/breaking-changes-in-v2.md) : List of breaking changes in goldmark v2 that you should be aware of when migrating your extension from v1 to v2.
- [How to create an extension](./references/how-to-create-an-extension.md) : Guide on how to create a goldmark extension in v2, including the new extension pattern and how to implement parser and renderer extensions.

## Migration steps
### Overview of the migration process

- Create a migration plan for the extension.
- **MUST** ask human to confirm that the migration plan is acceptable before proceeding with the migration.
- **MUST** ask human to how to test the extension after migration before proceeding with the migration.
  - e.g. : "How do you want to test the extension after migration? Do you have any test cases or examples that you want to use for testing?"
- Execute the migration plan to update the extension code to be compatible with goldmark v2.
- Update the test cases to ensure that the extension works as expected with goldmark v2.
- Test the extension with goldmark v2 to ensure that it works as expected. If there are any issues, fix them and re-test until the extension works as expected.
- Update the documentation to reflect any changes made during the migration process.

### Create a migration plan
#### Task

- Make sure you have read and understood the [Breaking changes in v2](../../references/breaking-changes-in-v2.md) document.
- Make sure you have read and understood the [How to create an extension](./references/how-to-create-an-extension.md) document.
- You create a ./features/goldmark-migration-plan.md file that contains a migration plan for the extension. 

#### Key points to consider when migrating your extension
##### Extension options

- If the extension uses "unified" options for both parser and renderer, they should be split into separate options for each.
  - e.g. :
    - v1
      ```go
      type Option interface {
          myOption()
      }

      type ParserOption interface {
          Option
          applyParserOption(*parserConfig)
      }

      type RendererOption interface {
          Option
          applyRendererOption(*rendererConfig)
      }

      func New(opts ...Option) goldmark.Extender { // takes unified options
          // ...
      }
      ```
    - v2
      ```go
      type ParserOption interface {
          applyParserOption(*parserConfig)
      }

      type HTMLRendererOption interface { // explicitly named for **HTML**
          applyRendererOption(*htmlRendererConfig) // you can access the shared renderer config like `XHTML` or `Unsafe` in the renderer config
      }

      func NewParser(opts ...ParserOption) parser.Extension { // takes parser options
          // ...
      }

      var Parser = NewParser() // Default instance of parser extension

      func NewHTMLRenderer(opts ...HTMLRendererOption) html.Extension { // takes renderer options
          // ...
      }

      var HTMLRenderer = NewHTMLRenderer() // Default instance of renderer extension
      ```

##### AST nodes

- use `text.Value`(single line), `text.MultiLineValue`(multi-line) instead of `[]byte` for values that can be parsed from source text in inline AST nodes.
  - In your parser, you must choose `text.Decoder` implementation to decode the source value
    - `text.IdentityDecoder` : for raw contents like inline HTMLs, inline code, etc.
    - `reader.Decoder` : other contents like text, links, etc. This decoder decodes entity references, `\` escapes, etc.
  - In most cases, you will choose `text.Decoder`. **DO NOT** use `text.IdentityDecoder` unless you have a clear intention to do so.
- use `text.Lines` instead of `[]text.Segment` for values in block AST nodes that have **raw contents** like HTML blocks, code blocks, etc. 
- Properties in AST Dump should be `text.Value` as possible.
  - e.g.
    - OK:
      ```
      // Dump implements Node.Dump.
      func (n *Text) Dump(_ []byte) *NodeDump {
      	m := map[string]any{
      		"Value": n.Value, // text.Value
      	}
      	fs := textFlagsString(n.flags)
      	if len(fs) != 0 {
      		m["Flags"] = fs
      	}
      	return NewNodeDump(n, m)
      }
      ```
    - Not OK:
      ```
      // Dump implements Node.Dump.
      func (n *Text) Dump(source []byte) *NodeDump {
      	m := map[string]any{
      		"Value": n.Value.Str(source), // string
      	}
      	fs := textFlagsString(n.flags)
      	if len(fs) != 0 {
      		m["Flags"] = fs
      	}
      	return NewNodeDump(n, m)
      }
      ```
- In v2, attribute values are `text.Value` which has almost the same specification as HTML attributes.
  - Therefore, if the project were using non-string attributes in v1, human must decide on one of the following policies:
     - Use the `goldmark_v1_attribute` build tag to continue using v1 attributes as they are.
     - Convert attribute values to strings to comply with the v2 specification.
  - **MUST** ask human to decide on one of the above policies before proceeding with the migration.

##### Parsing

- In v2, all nodes have a start position. goldmark/v2 automatically sets the start position to the node. However, if you want to customize the start position, you need to call `SetPos` appropriately.

##### HTML Rendering

- `text.Value` and `text.Lines` can be rendered using the `WriteTo` method whenever possible. Also, the output destination of `WriteTo` should use `html.ContextHTMLWriter(rc)` or `html.ContextTextWriter(rc)`.
   - e.g. :
     ```go
     tw := html.ContextTextWriter(rc)
     _, _ = n.Value.WriteTo(tw, source)
     ```
   - `WriteTo` is fast because it does not allocate new memory. On the other hand, if you write `Value` directly like `tw.Write(n.Value.Value(source))`, it may copy the contents of `Value`, which can degrade performance.

##### Recommended naming convention(for public stuff)

- Use `myext.NewParser()` and `myext.NewHTMLRenderer()` for the extension constructors.
  - e.g. : `meta` extension
    - `meta.NewParser()`, `meta.NewHTMLRenderer()`
- Use `myext.Parser` and `myext.HTMLRenderer` as the default extension values.
  - e.g. : `var Parser = NewParser()`, `var HTMLRenderer = NewHTMLRenderer()`
- Use `myext.ParserOption` and `myext.HTMLRendererOption` for functional options.
   - e.g. : `type ParseOption func(*parserConfig)`, `type HTMLRendererOption func(*htmlRendererConfig)`

### Execute migration plan
- Make sure you are on a branch that is not `main` or `master`. User must create a new branch like 'v2' to work on the migration before using this skill.
  - If you are on `main` or `master`, **STOP** this skill and ask human to create a new branch like 'v2' to work on the migration.
- Make sure `go.mod` file is updated to use `github.com/yuin/goldmark/v2` instead of `github.com/yuin/goldmark`. User must add `goldmark/v2` before using this skill.
  - If `go.mod` file is not updated, **STOP** this skill and ask human to update `go.mod` file to use `github.com/yuin/goldmark/v2` instead of `github.com/yuin/goldmark`.
- Update the module path in your `go.mod` file with new major version. For example, change `github.com/you/yourextension` to `github.com/you/yourextension/v2`.
  - **MUST** ask human to make sure that the module path is updated in `go.mod` file before proceeding with the migration.
    - If human confirms that the module path is updated, proceed with the migration, otherwise, **STOP** this skill and ask human to update the module path in `go.mod` file with new major version.


