A Markdown to Markdown processor that supports include directives and code snippet inclusion for reusable content composition... A templating system for Markdown that outputs to Markdown.
md2md allows you to compose documents from reusable markdown partials and code snippets using include directives. This enables you to:
- Reuse content across multiple documents
- Include code files with syntax highlighting and line selection
- Maintain consistency in documentation
- Organize content into modular, reusable pieces
- Process files individually or in batch mode
- Include directives - Compose documents from reusable partials
- Code snippet inclusion - Include code files with syntax highlighting
- Batch processing - Process entire directories at once
- Interactive TUI - Beautiful terminal interface for monitoring progress
- CI/automation mode - Non-interactive processing for pipelines
- Force mode - Automatic overwrite and directory creation
- Detailed reporting - Comprehensive processing statistics
- Input/Output validation - Enforces consistent file/directory types
!include()- Include markdown partials with optional variables and titles!codesnippet()- Include code files with syntax highlighting and line selection
cargo install --git https://github.com/funnierinspanish/md2md.gitDownload the latest release for your platform from the GitHub releases page:
Linux (x86_64):
# Download and extract
curl -L https://github.com/funnierinspanish/md2md/releases/latest/download/md2md-x86_64-unknown-linux-gnu.tar.gz | tar xz
# Make executable and move to PATH
chmod +x md2md-x86_64-unknown-linux-gnu
sudo mv md2md-x86_64-unknown-linux-gnu /usr/local/bin/md2mdLinux (x86_64, static musl):
# Download and extract (no glibc dependencies)
curl -L https://github.com/funnierinspanish/md2md/releases/latest/download/md2md-x86_64-unknown-linux-musl.tar.gz | tar xz
# Make executable and move to PATH
chmod +x md2md-x86_64-unknown-linux-musl
sudo mv md2md-x86_64-unknown-linux-musl /usr/local/bin/md2mdmacOS (Intel):
# Download and extract
curl -L https://github.com/funnierinspanish/md2md/releases/latest/download/md2md-x86_64-apple-darwin.tar.gz | tar xz
# Make executable and move to PATH
chmod +x md2md-x86_64-apple-darwin
sudo mv md2md-x86_64-apple-darwin /usr/local/bin/md2mdmacOS (Apple Silicon):
# Download and extract
curl -L https://github.com/funnierinspanish/md2md/releases/latest/download/md2md-aarch64-apple-darwin.tar.gz | tar xz
# Make executable and move to PATH
chmod +x md2md-aarch64-apple-darwin
sudo mv md2md-aarch64-apple-darwin /usr/local/bin/md2mdWindows:
- Download
md2md-x86_64-pc-windows-msvc.zipfrom the releases page - Extract the ZIP file
- Move
md2md.exeto a directory in your PATH
git clone https://github.com/funnierinspanish/md2md.git
cd md2md
cargo build --release
# Binary will be in target/release/md2mdmd2md --version# Process a single file with partials
md2md input.md -p partials -o output.md
# Include code snippets with syntax highlighting
# Use !codesnippet(file.rs, lang="rust") in your markdown
# Batch process directory
md2md src-docs -p partials -o output-docs --batch
# CI mode with automatic overwrite
md2md src-docs -p partials -o output-docs --batch --ci --forcemd2md supports two types of directives for content inclusion:
Use include directives to include markdown partials:
!include(your-partial.md)Add an automatic title to the included content:
!include(your-partial.md, title="Section Title")
!include(your-partial.md, title="Section Title", title-level=2)Pass variables to be substituted in the included content:
!include(your-partial.md, values=[variable_name="Value", another_var="Another Value"])!include(your-partial.md, title="Getting Started", title-level=2, values=[project_name="MyProject", author="John Doe"])Within your partial files, use this syntax for variables:
# Welcome to {% project_name %}!
Created by: {% author %}
Optional with default: {% optional_var || "default value" %}Use codesnippet directives to include code files with syntax highlighting:
!codesnippet(src/main.rs, lang="rust")!codesnippet(utils.py, lang="python", start=10, end=25)
!codesnippet(config.js, lang="javascript", end=15)
!codesnippet(helpers.py, lang="python", start=20)!codesnippet(data.txt)Both include and codesnippet directives follow the same path resolution rules:
- Partials directory - Plain filenames are resolved relative to the partials directory (
-pflag) - Relative paths - Paths starting with
../are resolved relative to the current file - Absolute paths - Paths starting with
/are used as-is
Given this file structure:
examples/
├── source-documents/
│ ├── api.md
│ └── mixed-demo.md
├── partials/
│ ├── header.md
│ └── footer.md
└── test-code/
├── hello.rs
└── example.py
Your docs/api.md can include partials and code:
!include(header.md)
# API Documentation
!codesnippet(../test-code/hello.rs, lang="rust")
Your main content here...
!include(footer.md)Process with:
md2md docs/api.md -p partials -o output/api.mdYielding:
fn main() {
println!("Hello, world!");
let x = 42;
let y = x * 2;
println!("Result: {}", y);
if x > 0 {
println!("x is positive");
}
}As you can see, nothing breaks!
md2md [OPTIONS] <INPUT_PATH>
Arguments:
<INPUT_PATH> The source file or directory to be processed
Options:
-p, --partials-path <PARTIALS> The directory containing the partials. Default: `partials` [default: partials]
-o, --output-path <OUTPUT> Output path (file or directory) [default: out]
-b, --batch Process directories recursively (batch mode)
-v, --verbose Verbose output
-c, --ci Disable TUI interface (use simple console output)
-f, --force Force overwrite existing files and create directories without prompting
--fix-code-fences <LANGUAGE> Fix code fences that don't specify a language by adding a default language [default: text]
-h, --help Print help (see more with '--help')
-V, --version Print versionmd2md enforces consistent input/output types:
- File input → File output:
input.md→output.md - Directory input → Directory output:
src-docs/→output-docs/ - Use trailing slash (
/) to explicitly indicate directory output - Files without extensions are allowed as output for file input
# ✅ Valid: File → File
md2md input.md -p partials -o output.md
# ✅ Valid: Directory → Directory
md2md src-docs -p partials -o output-docs --batch
# ✅ Valid: Directory → Directory (explicit)
md2md src-docs -p partials -o output-docs/ --batch
# ❌ Invalid: File → Directory
md2md input.md -p partials -o output-dir/
# ❌ Invalid: Directory → File
md2md src-docs -p partials -o output.md --batchSee the examples/ directory for demonstrations of md2md features:
# Process include examples
md2md examples/source-documents/demo.md -p examples/partials -o output/demo.md
# Process code snippet examples
md2md examples/source-documents/codesnippet-demo.md -p examples/partials -o output/codesnippet-demo.md
# Process mixed directives
md2md examples/source-documents/mixed-directives.md -p examples/partials -o output/mixed.md
# Batch process directory
md2md examples/source-documents -p examples/partials -o output-docs --batchmd2md processes files through these steps:
- Parse input files for include and codesnippet directives
- Resolve partial and code file paths according to resolution rules
- Include partial content and code snippets recursively (supports nested includes)
- Process variable substitution in partials
- Write processed output to destination
The tool supports both single-file processing and batch directory processing with comprehensive error handling and progress reporting.
md2md uses the term "partials" to describe reusable content pieces, although the CLI flag remains --templates-path for backward compatibility.
- Definition: Reusable pieces of content that can be included in multiple documents
- Examples: Headers, footers, common sections, shared content blocks
- Usage: Include directives like
!include (header.md)pull in the content of partials
- Definition: Structural layouts that define the overall format of documents
- Examples: HTML page layouts, document skeletons with placeholders
- md2md approach: We compose documents from partials rather than filling template placeholders
The content pieces in md2md are:
- Self-contained - Complete markdown content that can stand alone
- Reusable - Used across multiple documents
- Composable - Combined to build larger documents
- Content-focused - Contain actual content rather than structural placeholders
This aligns with the "partial" concept used in many templating systems where partials are reusable content components.
The CLI flag remains --templates-path for backward compatibility, but conceptually these are partials directories containing reusable content pieces.