> ## Documentation Index
> Fetch the complete documentation index at: https://lunr-f6858e75.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Formatters

> Render changelogs in different output formats

<Note>
  HelixCommit includes five built-in formatters for rendering changelogs: Markdown, HTML, plain text, JSON, and YAML.
</Note>

## Formatter comparison

| Feature              | Markdown | HTML    | Text      | JSON  | YAML |
| -------------------- | -------- | ------- | --------- | ----- | ---- |
| **GitHub releases**  | Best     | Works   | Plain     | No    | No   |
| **Websites**         | Good     | Best    | No        | API   | API  |
| **Email**            | Varies   | Best    | Universal | No    | No   |
| **Terminal**         | Good     | No      | Best      | Parse | Good |
| **Programmatic use** | Parse    | Parse   | Parse     | Best  | Best |
| **CI/CD pipelines**  | Good     | Limited | Good      | Best  | Best |

***

## Markdown formatter

Generate GitHub-compatible Markdown.

### render\_markdown()

```python theme={}
from helixcommit.formatters.markdown import render_markdown

markdown = render_markdown(changelog: Changelog) -> str
```

<ParamField path="changelog" type="Changelog" required>
  Structured changelog object to render.
</ParamField>

**Returns:** Formatted Markdown string

### Example

```python theme={}
from helixcommit.formatters.markdown import render_markdown

markdown = render_markdown(changelog)

# Save to file
Path("RELEASE_NOTES.md").write_text(markdown)

# Print to console
print(markdown)
```

### Output format

<Frame>
  ```markdown theme={}
  ## Release v2.0.0
  _Released on 2025-11-13_

  ### Breaking Changes
  - **api**: Change authentication flow (abc123)

  ### Features
  - **ui**: Add dashboard component (def456)
  - **api**: Implement rate limiting (ghi789)

  ### Bug Fixes
  - Fix memory leak in parser (jkl012)

  [View full changelog](https://github.com/owner/repo/compare/v1.0.0...v2.0.0)
  ```
</Frame>

***

## HTML formatter

Generate styled HTML output.

### render\_html()

```python theme={}
from helixcommit.formatters.html import render_html

html = render_html(changelog: Changelog) -> str
```

<ParamField path="changelog" type="Changelog" required>
  Structured changelog object to render.
</ParamField>

**Returns:** Formatted HTML string with embedded CSS

### Example

```python theme={}
from helixcommit.formatters.html import render_html

html = render_html(changelog)

# Save to file
Path("changelog.html").write_text(html)

# Serve on website
return Response(html, mimetype='text/html')
```

### Output format

```html theme={}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Release v2.0.0</title>
  <style>
    /* Embedded CSS styles */
  </style>
</head>
<body>
  <div class="release">
    <h2>Release v2.0.0</h2>
    <p class="date">Released on November 13, 2025</p>
    <!-- Sections and items -->
  </div>
</body>
</html>
```

***

## Text formatter

Generate plain text output.

### render\_text()

```python theme={}
from helixcommit.formatters.text import render_text

text = render_text(changelog: Changelog) -> str
```

<ParamField path="changelog" type="Changelog" required>
  Structured changelog object to render.
</ParamField>

**Returns:** Plain text string

### Example

```python theme={}
from helixcommit.formatters.text import render_text

text = render_text(changelog)

# Save to file
Path("CHANGES.txt").write_text(text)

# Send via email
send_email(to="team@example.com", body=text)

# Post to Slack
slack_client.post_message(channel="#releases", text=text)
```

### Output format

```text theme={}
================================================================================
Release v2.0.0
Released on 2025-11-13
================================================================================

BREAKING CHANGES
----------------
* api: Change authentication flow (abc123)

FEATURES
--------
* ui: Add dashboard component (def456)
* api: Implement rate limiting (ghi789)

BUG FIXES
---------
* Fix memory leak in parser (jkl012)

Full changelog: https://github.com/owner/repo/compare/v1.0.0...v2.0.0
```

***

## JSON formatter

Generate machine-readable JSON output for programmatic use.

### render\_json()

```python theme={}
from helixcommit.formatters.json import render_json

json_output = render_json(changelog: Changelog, *, indent: int = 2) -> str
```

<ParamField path="changelog" type="Changelog" required>
  Structured changelog object to render.
</ParamField>

<ParamField path="indent" type="int" default="2">
  Number of spaces for JSON indentation.
</ParamField>

**Returns:** JSON string representation of the changelog

### Example

```python theme={}
from helixcommit.formatters.json import render_json

json_output = render_json(changelog)

# Save to file
Path("changelog.json").write_text(json_output)

# Parse and process
import json
data = json.loads(json_output)
for section in data["sections"]:
    print(f"{section['title']}: {len(section['items'])} items")
```

### Output format

```json theme={}
{
  "version": "v2.0.0",
  "date": "2025-11-13T12:00:00+00:00",
  "sections": [
    {
      "title": "Features",
      "items": [
        {
          "title": "Add dashboard component",
          "type": "feat",
          "scope": "ui",
          "breaking": false,
          "references": {
            "commit": "def456",
            "pr": "https://github.com/owner/repo/pull/42"
          }
        }
      ]
    }
  ],
  "metadata": {
    "compare_url": "https://github.com/owner/repo/compare/v1.0.0...v2.0.0"
  }
}
```

***

## YAML formatter

Generate human-readable YAML output for CI/CD pipelines.

### render\_yaml()

```python theme={}
from helixcommit.formatters.yaml import render_yaml

yaml_output = render_yaml(changelog: Changelog, *, default_flow_style: bool = False) -> str
```

<ParamField path="changelog" type="Changelog" required>
  Structured changelog object to render.
</ParamField>

<ParamField path="default_flow_style" type="bool" default="False">
  If True, use flow style (inline) for collections.
</ParamField>

**Returns:** YAML string representation of the changelog

### Example

```python theme={}
from helixcommit.formatters.yaml import render_yaml

yaml_output = render_yaml(changelog)

# Save to file
Path("changelog.yaml").write_text(yaml_output)

# Use with CI/CD tools
with open(".release-data.yaml", "w") as f:
    f.write(yaml_output)
```

### Output format

```yaml theme={}
version: v2.0.0
date: '2025-11-13T12:00:00+00:00'
sections:
  - title: Features
    items:
      - title: Add dashboard component
        type: feat
        scope: ui
        breaking: false
        references:
          commit: def456
          pr: https://github.com/owner/repo/pull/42
metadata:
  compare_url: https://github.com/owner/repo/compare/v1.0.0...v2.0.0
```

***

## Using all formatters

Generate output in all formats:

```python theme={}
from pathlib import Path
from helixcommit.formatters import markdown, html, text, json, yaml

# Generate all formats
markdown_output = markdown.render_markdown(changelog)
html_output = html.render_html(changelog)
text_output = text.render_text(changelog)
json_output = json.render_json(changelog)
yaml_output = yaml.render_yaml(changelog)

# Save to files
Path("RELEASE_NOTES.md").write_text(markdown_output)
Path("changelog.html").write_text(html_output)
Path("CHANGES.txt").write_text(text_output)
Path("changelog.json").write_text(json_output)
Path("changelog.yaml").write_text(yaml_output)

print("✓ Generated release notes in all formats")
```

***

## Custom formatters

Create your own formatter by implementing a rendering function:

### Basic custom formatter

```python theme={}
from helixcommit.models import Changelog, ChangelogSection

def custom_formatter(changelog: Changelog) -> str:
    """Generate custom format release notes."""
    lines = []
    
    # Header
    lines.append(f"# Release {changelog.version}")
    lines.append(f"Date: {changelog.release_date.strftime('%Y-%m-%d')}")
    lines.append("")
    
    # Sections
    for section in changelog.sections:
        lines.append(f"## {section.title}")
        
        for item in section.items:
            # Format: "- [TYPE] Description (SHA)"
            commit_type = item.commit_type.upper()
            sha_short = item.commit_sha[:7]
            lines.append(f"- [{commit_type}] {item.description} ({sha_short})")
        
        lines.append("")
    
    return "\n".join(lines)

# Use custom formatter
output = custom_formatter(changelog)
print(output)
```

### Template-based formatting

For more complex customization, use Jinja2 templates:

```python theme={}
from jinja2 import Template
from helixcommit.models import Changelog

# Define template
template_string = """
# {{ changelog.version }}

Released: {{ changelog.release_date.strftime('%B %d, %Y') }}

{% for section in changelog.sections %}
## {{ section.title }}

{% for item in section.items %}
- {{ item.description }}
  {%- if item.scope %} ({{ item.scope }}){% endif %}
  {%- if item.breaking %} ⚠️ BREAKING{% endif %}
{% endfor %}

{% endfor %}
"""

def template_formatter(changelog: Changelog) -> str:
    """Render using Jinja2 template."""
    template = Template(template_string)
    return template.render(changelog=changelog)

# Use template formatter
output = template_formatter(changelog)
```

***

## Complete example

```python theme={}
from datetime import datetime
from pathlib import Path
from helixcommit.changelog import ChangelogBuilder
from helixcommit.formatters import markdown, html, text, json, yaml
from helixcommit.git_client import CommitRange, GitRepository

def generate_all_formats(repo_path: Path, since: str, until: str):
    """Generate release notes in all formats."""
    
    # Get commits
    repo = GitRepository(repo_path)
    commits = list(repo.iter_commits(
        CommitRange(since=since, until=until)
    ))
    
    # Build changelog
    builder = ChangelogBuilder(include_scopes=True)
    changelog = builder.build(
        version=until,
        release_date=datetime.now(),
        commits=commits,
        commit_prs={},
        pr_index={}
    )
    
    # Generate all formats
    formats = {
        "RELEASE_NOTES.md": markdown.render_markdown(changelog),
        "changelog.html": html.render_html(changelog),
        "CHANGES.txt": text.render_text(changelog),
        "changelog.json": json.render_json(changelog),
        "changelog.yaml": yaml.render_yaml(changelog)
    }
    
    # Save files
    output_dir = repo_path / "releases"
    output_dir.mkdir(exist_ok=True)
    
    for filename, content in formats.items():
        output_file = output_dir / filename
        output_file.write_text(content)
        print(f"✓ Generated {filename}")

# Usage
generate_all_formats(
    repo_path=Path("."),
    since="v1.0.0",
    until="v2.0.0"
)
```

***

## Next steps

<CardGroup cols={2}>
  <Card title="Changelog builder" icon="list" href="/api-reference/changelog" color="#0A6ACB">
    Build changelogs from commits
  </Card>

  <Card title="Output formats" icon="file-export" href="/output-formats" color="#F26419">
    Learn about format selection
  </Card>

  <Card title="Python API" icon="python" href="/api-reference/python-api" color="#F6A02D">
    Complete API reference
  </Card>

  <Card title="Examples" icon="code" href="/examples" color="#0A6ACB">
    See formatters in action
  </Card>
</CardGroup>
