Skip to main content

obsidian-export

Convert Obsidian-flavored Markdown to PDF and DOCX. Handles wikilinks, embeds, callouts, Mermaid diagrams, and frontmatter — producing clean, professional documents via a 5-stage pipeline (vault ops → preprocess → mermaid → SVG → pandoc).

Documentation | PyPI | Changelog

Installation

conda-forge (recommended)

Installs obsidian-export with pandoc included automatically. You must separately install tectonic >= 0.15 and librsvg (not yet available on all platforms via conda-forge). Run obsidian-export doctor to check.

conda install -c conda-forge obsidian-export

Or with pixi:

pixi global install obsidian-export

Note: The conda-forge package is pending review. Until it's accepted, install from source using pixi:

git clone https://github.com/neuralsignal/obsidian-export.git
cd obsidian-export
pixi install
pixi run obsidian-export --help

pip

pip install obsidian-export

With pip, you must separately install pandoc >= 3.5, tectonic >= 0.15, and librsvg. Run obsidian-export doctor to check.

Mermaid Support (optional)

For Mermaid diagram rendering, install Node.js >= 20 and mermaid-cli:

npm install -g @mermaid-js/mermaid-cli

Quick Start

# Convert with default settings
obsidian-export convert --input my_note.md --format pdf --output my_note.pdf

# Convert to DOCX
obsidian-export convert --input my_note.md --format docx --output my_note.docx

# Use a custom profile
obsidian-export convert --input my_note.md --format pdf --output my_note.pdf --profile my_brand

Profile Management

Profiles are YAML config files stored in ~/.obsidian-export/profiles/.

# Initialize directory structure and default profile
obsidian-export init

# Create a new profile (starts from defaults)
obsidian-export profile create my_brand

# Create from existing YAML
obsidian-export profile create my_brand --from existing_config.yaml

# List profiles
obsidian-export profile list

# Show profile contents
obsidian-export profile show my_brand

# Delete a profile
obsidian-export profile delete my_brand --yes

Custom Styles

Styles are LaTeX header templates. Place custom styles in ~/.obsidian-export/styles/<name>/header.tex.

Style resolution order:

  1. style_dir field in config (explicit path)
  2. Built-in styles (default)
  3. User styles in ~/.obsidian-export/styles/<name>/
  4. Treat style name as a filesystem path

Configuration

A config YAML can override any subset of defaults. Only include fields you want to change:

# Minimal override — everything else uses defaults
style:
  fontsize: "12pt"
  mainfont: "Georgia"
  line_spacing: 1.5

Full Config Reference

mermaid:
  mmdc_bin: "mmdc"          # Path to Mermaid CLI binary
  scale: 3                  # PNG render scale

obsidian:
  wikilink_strategy: "text"           # How to handle [[wikilinks]]
  url_strategy: "footnote_long"       # bare URL handling: keep|footnote_long|footnote_all|strip
  url_length_threshold: 60            # URL length for footnote_long strategy

pandoc:
  from_format: "gfm-tex_math_dollars+footnotes" # Pandoc input format

style:
  name: "default"                     # Style name (resolves to header.tex template)
  geometry: "a4paper,margin=25mm"     # Page geometry
  fontsize: "10pt"                    # Base font size
  mainfont: ""                        # Main font (XeLaTeX)
  sansfont: ""                        # Sans font
  monofont: ""                        # Mono font
  greek_font: ""                      # Fallback font for Greek glyphs (e.g. "DejaVu Serif"); empty disables
  linkcolor: "NavyBlue"              # Internal link color
  urlcolor: "NavyBlue"               # URL color
  line_spacing: 1.0                  # Line spacing multiplier
  table_fontsize: "small"            # Font size in tables
  image_max_height_ratio: 0.40       # Max image height as fraction of page
  url_footnote_threshold: 60         # URL length threshold for footnoting
  header_left: ""                    # Left header (supports {doc_title}, {logo_path})
  header_right: ""                   # Right header
  footer_left: ""                    # Left footer
  footer_center: "\\thepage"         # Center footer
  footer_right: ""                   # Right footer
  logo: ""                           # Logo filename (relative to config dir)
  style_dir: ""                      # Explicit style directory path
  unicode_chars:                     # Unicode → LaTeX substitutions
    "⚠": "\\ensuremath{\\triangle}"
    "✅": "\\ensuremath{\\checkmark}"
    "❌": "\\ensuremath{\\times}"
    # ... see default.yaml for full list
  callout_colors:
    note: [219, 234, 254]
    tip: [220, 252, 231]
    warning: [254, 243, 199]
    danger: [254, 226, 226]
  brand_colors:                      # Custom named colors (empty = none)
    petrol: [20, 75, 95]
    turkis: [0, 152, 160]
  heading_styles:                    # Custom heading formats (empty = default)
    - level: "section"               # LaTeX level: section, subsection, subsubsection
      size: "Large"                  # LaTeX size: huge, LARGE, Large, large, normalsize
      bold: true
      sans: true                     # Use sans-serif font
      color: "petrol"               # Reference to brand_colors name or LaTeX color
      uppercase: false
    - level: "subsection"
      size: "large"
      bold: true
      sans: true
      color: "turkis"
      uppercase: true                # Render heading text in UPPERCASE
  title_style: null                  # Custom title block (null = default)
    # size: "huge"
    # bold: true
    # sans: true
    # color: "petrol"
    # date_visible: true
    # vskip_after: "2em"

Python API

from pathlib import Path
from obsidian_export import run
from obsidian_export.config import default_config, load_config

# Using defaults
config = default_config()
run(Path("my_note.md"), Path("output.pdf"), "pdf", config)

# Using a config file
config = load_config(Path("my_config.yaml"))
run(Path("my_note.md"), Path("output.pdf"), "pdf", config)

What It Does

Obsidian Syntax Result
![[embed]] Resolved inline (content inlined)
[[Entity|Display]] Replaced with Display
[[Entity]] Replaced with Entity
> [!note] callouts Colored boxes (PDF) or blockquotes (DOCX)
```mermaid Rendered to PNG
## Relations section Removed
YAML frontmatter Title extracted, tags → keywords, rest removed
$25/user Safe literal dollar sign

License

MIT

Release files for obsidian-export 0.6.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for obsidian-export 0.6.3
File Size Uploaded
obsidian_export-0.6.3.tar.gz 29.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for obsidian-export 0.6.3
File Interpreter ABI Platform
obsidian_export-0.6.3-py3-none-any.whl Python 3 none any Details

Total release size:70.5 kB

Release files / obsidian_export-0.6.3.tar.gz

Download URL obsidian_export-0.6.3.tar.gz
Size 29.0 kB
Tags Source
SHA-256 checksum
How to use checksums
eecd2c39a70d619550b20b2977ba62966bacfb0184d980dfef06dc1e146cfc67
BLAKE2b-256 checksum
How to use checksums
d9bde8fb66a815c48b50194908334ecfbffd7f9cc71ddd474473671d5e4a3b25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.

Transparency log

Release files / obsidian_export-0.6.3-py3-none-any.whl

Download URL obsidian_export-0.6.3-py3-none-any.whl
Size 41.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
08803aeaf3c0a78d545f02eced6ef5af4285ef93277fe10949188bfb3d05bbeb
BLAKE2b-256 checksum
How to use checksums
1bc7981a7a774d2af13048abca924274cda27b9c3239b287616852619e5dc652
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.4

2 release files

This release

0.6.3 This release

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page