One URL in. Schema docs out.
Database → db2md → Markdown → Mermaid ER
Connect with any SQLAlchemy URL. Discover databases. Introspect tables, FKs, indexes, and comments. Write one Markdown file per database with a Mermaid ER diagram — no hardcoded names, no config file.
pip install 'db2md[postgres]'
db2md --url 'postgresql+asyncpg://user:pass@localhost:5432/postgres'
# → ./schemas/<database>.md
Full documentation: edwinalkins.github.io/db2md
MkDocs integration: generate into docs/schemas/ then enable Mermaid superfences — see docs/integrate-mkdocs.md.
Why db2md?
| Async-native | SQLAlchemy 2.x + async drivers (asyncpg, aiomysql, aiosqlite) |
| Zero hardcoding | Everything comes from introspection |
| Docs you can commit | Markdown + Mermaid — preview on GitHub, MkDocs, Notion… |
| Library + CLI | Script it, or run db2md in CI |
Install
pip install 'db2md[postgres]' # or [mysql] / [sqlite] / [all]
# From this repo
uv sync --extra postgres
| Dialect | Extra | Driver |
|---|---|---|
| PostgreSQL | postgres |
asyncpg |
| MySQL / MariaDB | mysql |
aiomysql |
| SQLite | sqlite |
aiosqlite |
CLI
# List databases (skips system catalogs by default)
db2md --url 'postgresql+asyncpg://user:pass@localhost:5432/postgres' --list
# Document every non-system database → ./schemas/<db>.md
db2md --url 'postgresql+asyncpg://user:pass@localhost:5432/postgres'
# Specific databases / output path
db2md \
--url 'postgresql+asyncpg://user:pass@localhost:5432/postgres' \
-d myapp -d analytics \
-o ./docs/db
uv run db2md --url 'sqlite+aiosqlite:///./app.db' -o ./schemas
Options
| Flag | Description |
|---|---|
-u, --url |
SQLAlchemy URL (or set DATABASE_URL) |
-o, --output |
Output directory (default: schemas/), or a file when documenting a single -d |
-d, --database |
Database to document (repeatable). Default: all non-system DBs |
--schema |
Schema/namespace (default: dialect-specific — public for PostgreSQL) |
--er-style |
Mermaid ER attribute style: compat (default), optional, minimal |
--list |
List databases and exit |
--include-system |
Include system databases |
-v, --verbose |
Debug logging |
--version |
Show version |
Bare dialects are upgraded to async drivers automatically (postgresql://… → postgresql+asyncpg://…, etc.).
Library API
import asyncio
from db2md import list_databases, generate_schema_markdown, export_schemas
URL = "postgresql+asyncpg://user:pass@localhost:5432/postgres"
async def main() -> None:
dbs = await list_databases(URL)
name, table_count, md = await generate_schema_markdown(URL, "myapp")
paths = await export_schemas(URL, "schemas")
print(dbs, name, table_count, paths)
asyncio.run(main())
Public symbols
| Symbol | Role |
|---|---|
list_databases(url, *, include_system=False) |
List database names (dialect-aware) |
generate_schema_markdown(url, database, *, schema=None) |
Returns (name, table_count, markdown) |
export_schemas(url, output="schemas", …) |
Write one .md file per database |
ColumnInfo / ForeignKeyInfo / IndexInfo / CheckConstraintInfo / TableInfo |
Introspection dataclasses |
Output
Each generated file contains:
- ER diagram — Mermaid
erDiagramwith PK/FK markers and cardinalities inferred from the constraints (1–0..1, 1–0..N, N–N) - Tables — columns, nullability, defaults, primary keys, comments
- Foreign keys, unique constraints, check constraints (name + SQL), indexes (columns + UNIQUE)
Example sketch:
# Database schema — `myapp`
> Auto-generated on 2026-08-02 12:00:00 UTC (schema `public`, 2 table(s)).
## ER diagram
```mermaid
erDiagram
"users" {
INTEGER id PK "Primary key"
VARCHAR(255) email
}
"notes" {
INTEGER id PK
INTEGER user_id FK
TEXT body "nullable"
}
"users" ||--o{ "notes" : "notes_user_id_fkey"
```
## Tables
### `users`
Application users
| Column | Type | Nullable | Default | PK | Comment |
|---|---|---|---|---|---|
| `id` | `INTEGER` | no | — | yes | Primary key |
…
Dialect behaviour
| Backend | Database discovery | Default schema |
|---|---|---|
| PostgreSQL | pg_database (non-template) |
public |
| MySQL / MariaDB | SHOW DATABASES |
current catalog |
| SQLite | single file DB | n/a |
| Other | current database only | dialect-dependent |
System databases skipped by default:
- PostgreSQL:
postgres,template0,template1 - MySQL / MariaDB:
mysql,information_schema,performance_schema,sys
Limitations
- Views, materialized views, and sequences are not documented yet (base tables only).
- Mermaid cardinalities are inferred from UNIQUE/PK constraints and FK nullability (junction tables → N–N). Details: docs/mermaid-cardinalities.md.
- Under SQLite,
-d/--databasedoes not switch files (one DB per path); a warning is logged.
Development
uv sync --all-extras --group dev
uv run ruff check src tests
uv run mypy src
uv run pytest
# Docs
uv sync --group docs
uv run mkdocs serve
See CONTRIBUTING.md.
License
MIT © edwinalkins
Metadata
Release files for db2md 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| db2md-0.2.0.tar.gz | 3.9 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| db2md-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 3.9 MB
Release files / db2md-0.2.0.tar.gz
| Download URL | db2md-0.2.0.tar.gz |
|---|---|
| Size | 3.9 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83e5f9a02bc94b00d13b3187dfe317669787131f4e887aaa3aac819c83cabc79
|
|
BLAKE2b-256 checksum How to use checksums |
63bdb8d747fcceac49d50ac4e9e69bf68967a20efa2216837aa3993fcf23b1c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / db2md-0.2.0-py3-none-any.whl
| Download URL | db2md-0.2.0-py3-none-any.whl |
|---|---|
| Size | 17.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be4b5596641bd9eebcef63fb634fed3696fd34f4614d0bf9404d2bcd4226fa50
|
|
BLAKE2b-256 checksum How to use checksums |
c8f8134c8b7117a362ac9eee293deee74614df7769ca80fba3648264b04ebc02
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|