Skip to content

Integrate with MkDocs

db2md emits plain Markdown with a fenced Mermaid erDiagram. That fits MkDocs (especially Material for MkDocs) with almost no glue code: generate files into your docs/ tree, enable Mermaid in mkdocs.yml, and link them from nav.

DATABASE_URL  →  db2md  →  docs/schemas/*.md  →  mkdocs build  →  site/

1. Install db2md in your project

pip install 'db2md[postgres]'   # or [mysql] / [sqlite] / [all]
# dependency for local / CI generation
uv add --dev 'db2md[postgres]'
# or one-off
uvx --from 'db2md[postgres]' db2md --help

Set a connection URL (do not commit secrets):

export DATABASE_URL='postgresql+asyncpg://user:pass@localhost:5432/postgres'

2. Generate schema docs into docs/

List databases first:

db2md --url "$DATABASE_URL" --list

Export one database to a dedicated page:

mkdir -p docs/schemas
db2md \
  --url "$DATABASE_URL" \
  -d myapp \
  -o docs/schemas/myapp.md

Export several databases into a directory (one .md file each):

db2md \
  --url "$DATABASE_URL" \
  -d myapp -d analytics \
  -o docs/schemas
# → docs/schemas/myapp.md
# → docs/schemas/analytics.md

Optional Mermaid attribute style (see CLI):

db2md --url "$DATABASE_URL" -d myapp -o docs/schemas/myapp.md --er-style compat
# compat (default) | optional | minimal

Regenerating before every docs build

Keep generated files out of git or commit them — both are valid.

A. Commit generated Markdown (simple previews on GitHub):

db2md --url "$DATABASE_URL" -d myapp -o docs/schemas/myapp.md
git add docs/schemas/myapp.md

B. Generate in CI only (always fresh):

# .github/workflows/docs.yml (excerpt)
- name: Generate DB docs
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
  run: |
    pip install 'db2md[postgres]'
    mkdir -p docs/schemas
    db2md --url "$DATABASE_URL" -d myapp -o docs/schemas/myapp.md

- name: Build MkDocs
  run: mkdocs build --strict

C. Makefile / script (local + CI):

.PHONY: schema-docs
schema-docs:
    mkdir -p docs/schemas
    db2md --url "$$DATABASE_URL" -d myapp -o docs/schemas/myapp.md

docs: schema-docs
    mkdocs serve

3. Enable Mermaid in MkDocs

Material for MkDocs loads Mermaid automatically when fences use the mermaid custom fence.

# mkdocs.yml
site_name: My project

theme:
  name: material

markdown_extensions:
  - tables
  - toc:
      permalink: true
  - pymdownx.superfences:
      custom_fences:
        - name: mermaid
          class: mermaid
          format: !!python/name:pymdownx.superfences.fence_code_format

nav:
  - Home: index.md
  - Database:
      - Application schema: schemas/myapp.md
      # - Analytics: schemas/analytics.md

Then:

mkdocs serve    # http://127.0.0.1:8000
mkdocs build --strict

Without Material

Any MkDocs theme works if you keep the same pymdownx.superfences Mermaid fence and load a Mermaid runtime, for example:

extra_javascript:
  - https://unpkg.com/mermaid@11/dist/mermaid.min.js

Minimal wrapper page (optional)

If you prefer a short hand-written intro above the generated file, either:

  • paste/include the generated content, or
  • point nav straight at schemas/myapp.md (simplest), or
  • use a plugin such as mkdocs-include-markdown-plugin:
# Database

Schema exported with [db2md](https://github.com/edwinalkins/db2md).

{%
  include-markdown "schemas/myapp.md"
%}

4. What you get in the site

Each generated page typically contains:

  1. A title (# Database schema — …)
  2. A Mermaid erDiagram (entities, PK/FK markers, inferred cardinalities)
  3. Per-table sections: columns, FKs, uniques, checks, indexes

MkDocs turns ### \table_name`` headings into TOC entries — useful for large schemas.

5. Large schemas

Full ER diagrams with dozens of tables are valid but can be slow or hard to read in the browser.

Practical patterns:

Approach How
One page per database Default db2md behaviour (-o docs/schemas)
Split by schema Run db2md several times with --schema public, --schema audit, …
Commit overview + detail Keep the generated file; add a hand-written page that embeds only a subset Mermaid diagram
CI artifact Generate on every docs deploy so the diagram always matches production

See also Mermaid cardinalities and Output format.

6. Other Mermaid diagrams — is another erDiagram style envisaged?

Today, db2md emits a single full erDiagram per database: entities with attributes, relationships with inferred cardinalities, plus the Markdown tables below.

Other diagram shapes are reasonable roadmap ideas, not competing replacements for the default:

Idea When it helps Status
Full erDiagram (current) Source of truth for columns + FKs Shipped (--er-style compat\|optional\|minimal only changes attributes)
Overview erDiagram (entities + relationships, little/no columns) 20+ tables; “map of the domain” Envisaged (e.g. future --er-detail=overview\|full)
Several ER diagrams (bounded contexts / prefixes) Monolith schemas Envisaged (filter by table prefix or schema already partially covered via --schema)
flowchart / graph of FK edges only Dependency / cascade mental model Possible later; less precise than ER for keys
classDiagram UML-oriented docs Possible; weaker fit for SQL nullability/PK semantics
External tools (PlantUML, Graphviz) Teams already standardised elsewhere Out of scope for core CLI; Markdown stays the portable format

Recommendation: keep one canonical erDiagram in the generated page (what MkDocs and GitHub already preview), and add optional “overview” or filtered diagrams later as extra fenced blocks in the same file — not a different primary format.

If you need a lighter diagram now without waiting for new flags:

  1. Generate with --er-style minimal (fewer markers on attributes).
  2. Or copy the ```mermaid block into a separate hand-maintained overview page and delete attribute lines inside entities (keep relationship lines).

7. Troubleshooting

Symptom Fix
Diagram shows as a code block Add the pymdownx.superfences Mermaid custom_fences block
mkdocs build --strict fails on missing file Run db2md before MkDocs, or commit docs/schemas/*.md
Diagram empty / broken in preview Upgrade db2md (≥ 0.2.0 fixed Mermaid attribute grammar); regenerate the .md
Page title looks odd Generated # Database schema — … becomes the page H1; rename via filename in nav labels
Secrets in CI Use DATABASE_URL from GitHub Actions secrets / OIDC — never hardcode passwords in mkdocs.yml

8. Library usage (same output)

import asyncio
from pathlib import Path
from db2md import export_schemas

async def main() -> None:
    await export_schemas(
        "postgresql+asyncpg://user:pass@localhost:5432/postgres",
        Path("docs/schemas"),
        databases=["myapp"],
    )

asyncio.run(main())

The files are identical to the CLI output and drop into MkDocs the same way.