Stop Wrestling with Markdown! Use mq Instead
What if I told you that developers waste hours every week copy-pasting between Markdown files, manually extracting code blocks, and writing brittle regex patterns that break on the first nested list? Here's the painful truth: Markdown is the universal language of documentation, LLM prompts, and technical content—yet we've had zero powerful tools to actually query it programmatically.
Until now.
Meet mq—the secret weapon that's making top developers abandon their hacky Python scripts and awk one-liners. Written in blazing-fast Rust, mq brings the legendary jq syntax to Markdown processing. Imagine extracting every Rust code block from 100 README files in under a second. Imagine filtering documentation sections by heading level with a single elegant query. Imagine transforming your entire docs pipeline from a fragile mess into a bulletproof, composable workflow.
This isn't a distant dream. This is mq—and it's about to change how you think about Markdown forever. Ready to see what you've been missing?
What is mq?
mq is a command-line tool that processes Markdown using a syntax similar to jq—the beloved JSON processor that revolutionized how developers work with structured data. Created by harehare and actively developed with rigorous CI/CD practices (including CodeSpeed performance benchmarking), mq fills a critical gap in the developer toolchain.
Built from the ground up in Rust, mq delivers exceptional performance while maintaining an intuitive, declarative query syntax. The project has gained significant traction in the developer community, particularly among teams working with Large Language Model (LLM) workflows, documentation systems, and content pipelines where Markdown serves as the primary data format.
Why is mq trending right now? Three explosive forces have converged:
-
The LLM Revolution: Markdown is the de facto input format for ChatGPT, Claude, and virtually every major language model. Developers desperately need tools to generate, filter, and transform Markdown at scale.
-
Documentation-First Culture: Modern development practices—from README-driven development to docs-as-code—have made Markdown the central nervous system of technical projects.
-
The jq Precedent: Once developers experienced
jq's power for JSON, they demanded equivalent capabilities for Markdown.mqanswers that call with surgical precision.
The project offers comprehensive tooling beyond the core binary: a web playground for experimentation, a full documentation book, IDE extensions for VSCode/Neovim/Zed, language bindings for Python/Go/Ruby/Java/Elixir, and even an experimental debugger (mq-dbg) for complex query inspection.
Key Features That Make mq Irresistible
mq isn't just another Markdown parser—it's a complete query and transformation engine. Here's what separates it from the pack:
-
Slice and Filter with Surgical Precision: Extract exactly the nodes you need—headings, code blocks, links, tables, lists—using CSS-selector-like syntax combined with
jq's powerful filtering expressions. No more regex nightmares. -
Map and Transform: Apply functions to modify content in-place. Change heading levels, rewrite URLs, reformat code blocks, or convert between Markdown and other formats.
-
Multiple Input/Output Formats: Beyond standard Markdown,
mqhandles MDX, HTML, plain text, CSV, and even raw binary formats. Output to Markdown, HTML, JSON, tables, or grep-compatible formats. -
Streaming Mode: Process massive files line-by-line without loading everything into memory. Essential for CI/CD pipelines and log analysis.
-
REPL for Rapid Iteration: Test queries interactively before committing them to scripts. The REPL (
mq repl) accelerates query development dramatically. -
Module System: Import custom functions with
includeandimport-module-names. Build reusable query libraries for your team. -
External Subcommands: Extend
mqinfinitely by placingmq-*executables in your PATH. The ecosystem grows without bloating the core. -
IDE-Grade Tooling: Full Language Server Protocol (LSP) support, VSCode extension with syntax highlighting, and plugins for Neovim and Zed. Write queries with autocomplete and inline errors.
-
Experimental Debugger: Step through complex queries with
mq-dbg—a feature virtually unheard of in CLI text processing tools.
Real-World Use Cases Where mq Dominates
1. LLM Prompt Engineering at Scale
Modern AI workflows are Markdown-heavy. You're crafting system prompts, few-shot examples, and output templates—all in Markdown. mq lets you extract, combine, and transform prompt components programmatically:
# Extract all examples from your prompt library
mq '.code("example")' prompts/*.md | mq -A 'join("\n---\n")' > combined_examples.md
2. Documentation Extraction and Reorganization
Need to generate a "Quick Start" from a comprehensive README? Or extract API references into a separate file?
# Pull just the Installation and Usage sections
mq -A 'section::section("Installation", "Usage")' README.md > quickstart.md
3. Code Audit and Dependency Analysis
Scan repositories for security issues, outdated dependencies, or coding patterns:
# Find all code blocks mentioning deprecated APIs
mq '.code | select(contains("deprecated_api"))' docs/**/*.md
4. Content Migration Pipelines
Converting from Confluence, Notion, or Word to a docs-as-code system? mq handles the heavy lifting:
# Convert Word doc, extract h2 sections as separate files
mq conv legacy.docx | mq -A 'section::sections() | section::by_level(2)' | \
mq --stream '.[] | tofile("section_\(.h.text).md")'
5. Automated Changelog Generation
Parse commit messages, PR descriptions, or issue comments formatted in Markdown:
# Extract all breaking changes from release notes
mq '.h(2) | select(contains("Breaking")) | ..' releases/*.md
Step-by-Step Installation & Setup Guide
Getting mq running takes under 60 seconds. Choose your preferred method:
Quick Install (Recommended)
The official installer handles everything automatically:
# One-liner installation
curl -sSL https://mqlang.org/install.sh | bash
This downloads the correct binary for your platform, installs to ~/.local/bin/, and updates your shell profile. Restart your terminal or run source ~/.bashrc (or equivalent) to activate.
Cargo (Rust Ecosystem)
# Latest stable from crates.io
cargo install mq-run
# Specific version from GitHub
cargo install --git https://github.com/harehare/mq.git mq-run --tag v0.5.29
# Bleeding edge
cargo install --git https://github.com/harehare/mq.git mq-run --bin mq
# With debugger support
cargo install --git https://github.com/harehare/mq.git mq-run --bin mq-dbg --features="debugger"
Pre-built Binaries
# macOS Apple Silicon
curl -L https://github.com/harehare/mq/releases/download/v0.5.29/mq-aarch64-apple-darwin \
-o /usr/local/bin/mq && chmod +x /usr/local/bin/mq
# Linux x86_64
curl -L https://github.com/harehare/mq/releases/download/v0.5.29/mq-x86_64-unknown-linux-gnu \
-o /usr/local/bin/mq && chmod +x /usr/local/bin/mq
# Linux ARM64
curl -L https://github.com/harehare/mq/releases/download/v0.5.29/mq-aarch64-unknown-linux-gnu \
-o /usr/local/bin/mq && chmod +x /usr/local/bin/mq
Homebrew
brew install mq
Docker
docker run --rm ghcr.io/harehare/mq:0.5.29
IDE Setup
- VSCode: Install from Visual Studio Marketplace or Open VSX
- Neovim: Follow mq.nvim instructions
- Zed: Install via zed-mq
Verify Installation
mq --version
mq repl # Start interactive mode to test queries
REAL Code Examples from mq
Let's dive into actual mq queries from the official documentation. These aren't toy examples—they're production-ready patterns you can use immediately.
Example 1: Extracting Headings with Precision
The most common Markdown operation is extracting structure. mq makes this effortless:
# Extract ALL headings from a document
mq '.h' README.md
# Extract only h1 headings (single level)
mq '.h(1)' README.md
# Extract h1 AND h2 headings (multiple specific levels)
mq '.h(1, 2)' README.md
# Extract headings from level 1 to 3 using a RANGE (inclusive)
mq '.h(1..3)' README.md
What's happening here? The .h selector targets heading nodes in the Markdown AST. The optional parentheses allow filtering by level—single integer for exact match, comma-separated for multiple levels, and .. range syntax for continuous spans. This produces clean, structured output without any regex gymnastics.
Example 2: Code Block Intelligence
Code blocks are the lifeblood of technical documentation. mq treats them as first-class queryable objects:
# Extract only Rust code blocks (filter by language)
mq '.code("rust")' example.md
# Extract code blocks containing specific text
mq '.code | select(contains("name"))' example.md
# Extract just the code VALUES (strip fences and language tags)
mq -A 'pluck(.code.value)' example.md
# Extract language identifiers for audit purposes
mq '.code.lang' documentation.md
# EXCLUDE JavaScript code blocks (negative filtering)
mq '.code | select(.code.lang != "js")' examples.md
The power move: Notice how .code returns an object with .lang and .value properties? This structured access means you can filter, transform, and extract with semantic understanding—not brittle pattern matching.
Example 3: Advanced Table and Link Processing
Markdown tables and links hold structured data that mq can unlock:
# Extract URLs from all links (flat list of destinations)
mq '.link.url' README.md
# Filter table cells containing specific text (2D traversal)
mq '.[][] | select(contains("name"))' data.md
# Complex boolean logic: select lists OR headers containing text
mq 'select(.[] || .h) | select(contains("name"))' docs.md
Critical insight: The .[][] syntax navigates table rows and cells—jq veterans will recognize this immediately. The select(.[] || .h) pattern demonstrates mq's support for boolean logic across node types, enabling sophisticated content detection.
Example 4: Section-Aware Document Surgery
This is where mq transcends simple extraction and enters document manipulation territory:
# Extract a complete section by its heading title
mq -A 'section::section("Installation")' README.md
# Get all top-level sections, then filter by heading level
mq -A 'section::sections() | section::by_level(2)' README.md
# Same approach with a RANGE of levels
mq -A 'section::sections() | section::by_level(1..2)' README.md
Why this matters: The section:: namespace provides document-structure-aware operations. Unlike naive text splitting, this respects Markdown's hierarchical nature—nested sections, code blocks within sections, and complex content boundaries are handled correctly.
Example 5: Composable Workflows with Pipes
mq shines in Unix pipelines, composing with itself and other tools:
# Convert Excel to Markdown, then extract all headings
mq conv report.xlsx | mq '.h'
# Convert Word document, extract specific section
mq conv document.docx | mq -A 'section::section("Summary")'
# Convert PDF slides and preview in terminal
mq conv slides.pdf | mq view
The philosophy: Each mq subcommand does one thing well. conv handles format conversion, then standard mq queries process the Markdown. This composability mirrors jq's design and the Unix philosophy—small, focused tools that combine into powerful workflows.
Example 6: CSV to Markdown Transformation
mq even bridges tabular data formats:
# Parse CSV with header row, convert to Markdown table
mq 'include "csv" | csv_parse(true) | csv_to_markdown_table()' example.csv
The include system loads external modules, extending mq's capabilities without bloating the core. The csv_parse(true) function enables header-aware parsing, and csv_to_markdown_table() handles alignment and formatting automatically.
Advanced Usage & Best Practices
Ready to level up? Here are pro strategies from the mq ecosystem:
Use -A for Aggregate Operations: When processing multiple files, -A collects all results into a single array—essential for cross-document analysis and pluck() operations.
Leverage Streaming for Massive Files: The --stream flag processes input line-by-line. Combine with --parallel-threshold (default: 10 files) for automatic parallelization across large file sets.
Build External Subcommands: Place mq-* executables in ~/.local/bin/ to extend functionality. mq --list reveals all available subcommands—built-in and custom.
Master Output Formats: Use -F json for API integration, -F html for web publishing, -F grep for integration with existing toolchains, and -F table for terminal-friendly display.
In-Place Editing with -U: The -U (update) flag modifies files directly—perfect for automated refactoring scripts. Alias carefully; this is powerful but irreversible.
Environment Variables via --args: Pass runtime configuration without hardcoding: mq --args version "1.2.3" '$version'.
Comparison with Alternatives
| Tool | Syntax | Speed | Markdown-Aware | LLM-Ready | IDE Support |
|---|---|---|---|---|---|
| mq | jq-like, declarative | ⚡ Rust-native, extremely fast | ✅ Full AST parsing | ✅ Designed for it | ✅ LSP + 3 editors |
sed/awk |
Imperative regex | Fast | ❌ Fragile pattern matching | ❌ Manual extraction | ❌ None |
pandoc |
Filters in Lua/Haskell | Moderate | ✅ Conversion-focused | ⚠️ Possible with filters | ⚠️ Limited |
Python markdown |
Python code | Slow | ⚠️ Extension-dependent | ⚠️ Requires coding | ❌ None |
jq + conversion |
jq (after conversion) | Fast | ❌ Requires pre-conversion | ⚠️ Indirect workflow | ❌ None |
The verdict: mq is the only tool that combines jq's query elegance with native Markdown semantics, Rust performance, and modern developer experience. For LLM workflows and documentation pipelines, there's simply no comparison.
FAQ
Q: Is mq stable for production use? A: The project is under active development with comprehensive CI/CD, CodeSpeed benchmarking, and regular releases. The core query syntax is stable; check release notes for breaking changes.
Q: Can mq handle MDX (Markdown + JSX)?
A: Yes! Use -I mdx to enable MDX parsing mode. mq understands JSX component syntax within Markdown documents.
Q: How does mq compare to using pandoc with custom filters?
A: pandoc excels at format conversion; mq excels at querying and transformation. For complex extraction and filtering operations, mq's declarative syntax is significantly more concise and maintainable than Lua or Haskell filters.
Q: Is there a JavaScript/TypeScript API?
A: Use mq-web via npm for browser and Node.js environments. It's a WebAssembly build with the full mq engine.
Q: Can I use mq in GitHub Actions?
A: Absolutely. The official harehare/setup-mq@v1 action installs mq in your workflow in seconds.
Q: How do I debug complex queries?
A: Install mq-dbg with --features="debugger" and use it to step through queries interactively, inspecting the AST at each stage.
Q: Does mq support custom functions?
A: Yes, via the module system (include, import-module-names) and external subcommands (mq-* executables). The LSP provides autocomplete for custom functions.
Conclusion
Markdown has been the unchallenged king of developer documentation for two decades. Yet until mq, we've lacked a tool worthy of its dominance—something that treats Markdown as queryable, transformable, composable data rather than plain text to be regex-mangled.
mq changes everything. It brings the ergonomic power of jq to the format that powers our READMEs, our LLM prompts, our documentation sites, and our technical content pipelines. Written in Rust for blazing performance. Designed with modern developer experience in mind—REPL, debugger, LSP, IDE extensions. Extensible through modules and external subcommands. Ready for the LLM era where Markdown isn't just documentation, but data.
The developers who master mq today will build documentation pipelines, content workflows, and AI integrations that leave others struggling with Python scripts and broken regex. The question isn't whether you'll adopt mq—it's whether you'll be ahead of the curve or catching up.
⭐ Star mq on GitHub and start transforming your Markdown workflow today. Your future self will thank you.
Try it instantly in the browser — no installation required.