DEV Community

Cover image for Markdown Linting in CI: markdownlint-cli2 vs gomarklint
Kazu
Kazu

Posted on

Markdown Linting in CI: markdownlint-cli2 vs gomarklint

You want to lint Markdown in CI.

You add markdownlint-cli2. Then you realize your CI job needs a Node.js
setup step. Then you need to pin a Node version. Then someone on your team
asks why the docs pipeline is touching Node at all.

There's another option.


Quick comparison

markdownlint-cli2 gomarklint
Runtime Node.js required None (single binary)
Install in CI npm install -g markdownlint-cli2 curl one-liner or GitHub Action
Rules 50+ 14 structural + link validation
HTTP link validation Needs a separate tool Built in
Config format .markdownlint.json / .markdownlint.yaml .gomarklint.yaml
Speed Fast ~170ms per 100k lines
Ecosystem npm Homebrew, binary download, go install

Installation

markdownlint-cli2 requires Node.js:

npm install -g markdownlint-cli2
markdownlint-cli2 "**/*.md"
Enter fullscreen mode Exit fullscreen mode

gomarklint is a single binary:

# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/shinagawa-web/gomarklint/main/install.sh | sh

# macOS via Homebrew
brew install shinagawa-web/tap/gomarklint
Enter fullscreen mode Exit fullscreen mode

No runtime. No package manager. Download it and it runs.


CI integration

This is where the difference is most visible.

markdownlint-cli2 in GitHub Actions

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install markdownlint-cli2
        run: npm install -g markdownlint-cli2

      - name: Lint Markdown
        run: markdownlint-cli2 "**/*.md"
Enter fullscreen mode Exit fullscreen mode

4 steps. Node.js setup adds ~15–20 seconds to the job.

gomarklint in GitHub Actions

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Lint Markdown
        uses: shinagawa-web/gomarklint-action@v1
Enter fullscreen mode Exit fullscreen mode

2 steps. No runtime to set up.

Or if you prefer the binary directly:

      - name: Install gomarklint
        run: curl -fsSL https://raw.githubusercontent.com/shinagawa-web/gomarklint/main/install.sh | sh

      - name: Lint Markdown
        run: gomarklint .
Enter fullscreen mode Exit fullscreen mode

Rules

markdownlint-cli2 has 50+ rules covering nearly every Markdown style
decision — list markers, emphasis style, line length, and more. If you
need fine-grained control over every aspect of your Markdown style, it's
the more comprehensive option.

gomarklint covers the rules that tend to matter most in practice:

  • Heading level progression (no jumping from H2 to H4)
  • Duplicate headings within a file
  • Single H1 per file
  • Blank lines around headings, lists, and code blocks
  • Fenced code blocks without a language identifier
  • Missing image alt text
  • Bare URLs
  • Empty links
  • Setext headings

All rules are on by default and configurable via .gomarklint.yaml.

If you need all 50+ markdownlint rules, gomarklint won't replace it today.
If the rules above cover your needs, you avoid the Node.js dependency.


Link validation

This is gomarklint's biggest differentiator.

markdownlint-cli2 checks Markdown syntax. It won't tell you whether
[docs](https://example.com/old-page) returns a 404. You need a separate
tool for that — lychee, markdown-link-check, or similar.

gomarklint validates external HTTP links as part of the lint pass:

# .gomarklint.yaml
rules:
  external-link:
    enabled: true
    timeoutSeconds: 5
    skipPatterns:
      - "localhost"
      - "example\\.com"
Enter fullscreen mode Exit fullscreen mode

One tool, one CI step.


Configuration

Both tools use YAML (or JSON for markdownlint). Here's a .gomarklint.yaml
that mirrors a typical markdownlint setup:

rules:
  heading-level:
    enabled: true
    minLevel: 2
  fenced-code-language:
    enabled: true
  external-link:
    enabled: true
    timeoutSeconds: 10
Enter fullscreen mode Exit fullscreen mode

Which one should you use?

Use markdownlint-cli2 if:

  • You already have Node.js in your pipeline
  • You need granular style rules (line length, list marker style, etc.)
  • You're in a JavaScript / frontend project where npm is already present

Use gomarklint if:

  • You want a single binary with no runtime dependencies
  • You want HTTP link validation without adding a second tool
  • Your CI environment doesn't have Node.js, or you'd rather not add it
  • You're in a Go, Rust, or other non-Node.js stack

pre-commit

Both tools support pre-commit.

# markdownlint-cli2
repos:
  - repo: https://github.com/DavidAnson/markdownlint-cli2-action
    rev: v17
    hooks:
      - id: markdownlint-cli2

# gomarklint
repos:
  - repo: https://github.com/shinagawa-web/gomarklint
    rev: v2.8.0
    hooks:
      - id: gomarklint
Enter fullscreen mode Exit fullscreen mode

Summary

markdownlint-cli2 is the mature, feature-rich choice with broad community
support. gomarklint trades rule count for zero runtime dependencies and
built-in link validation.

If you've ever added Node.js to a CI pipeline just to lint Markdown, it's
worth a look.

gomarklint on GitHub
Docs

Top comments (0)