CLI & Python API¶
erdify ships a command-line interface, a module entry point, and a Python API for programmatic use.
CLI Options¶
usage: erdify [-h] [-o OUTPUT] [--title TITLE] [--exclude [PATTERN ...]]
[--exclude-paths [PATTERN ...]] [--no-default-excludes]
[--sources [KIND ...]] [--include PATTERN [PATTERN ...]]
[--sql-dialect NAME] [--infer-keys] [--django-raw-types]
[--no-enums] [--no-relationships] [--format FMT [FMT ...]]
[--inject FILE] [--check] [-v]
input
Generate PlantUML ERD diagrams from SQLModel, SQLAlchemy, Django, Pydantic and
dataclass models
positional arguments:
input Directory or file with models (.py) or SQL DDL (.sql)
options:
-h, --help show this help message and exit
-o, --output OUTPUT Output .puml file (default: stdout)
--title TITLE Diagram title (default: 'Database ERD')
--exclude [PATTERN ...]
Glob patterns (case-sensitive) to exclude entities by
class name or table name, e.g. --exclude '*Link'
audit_log
--exclude-paths [PATTERN ...]
Glob patterns (case-sensitive) for models.py files to
skip before parsing, matched against the path relative
to input or any path segment, e.g. --exclude-paths
migrations legacy 'apps/experimental/*'
--no-default-excludes
Do not auto-skip models.py under venv/site-
packages/cache dirs (.venv, site-packages,
__pycache__, ...); scan them too
--sources [KIND ...] Restrict which model kinds become entities. Choices:
sqlmodel, sqlalchemy, django, dataclass, pydantic.
Default: all. e.g. --sources sqlmodel sqlalchemy for
DB tables only
--include PATTERN [PATTERN ...]
Glob patterns for files to scan (default: models.py).
A pattern with '/' matches the path relative to input
('**' crosses dirs); a pattern without '/' matches a
filename at any depth. Replaces the default, so list
models.py too if you want it, e.g. --include models.py
'**/models/*.py' tables.py
--sql-dialect NAME SQL dialect hint for parsing .sql DDL with the [sql]
extra (e.g. postgres, mysql, sqlite). Default: a
permissive generic read
--infer-keys For keyless models (Pydantic/dataclass), infer a
primary key from a field named 'id' and a foreign key
from '<x>_id' (target table '<x>')
--django-raw-types For Django models, show original field names
(CharField, TextField) instead of mapped Python types
(str, int, datetime)
--no-enums Skip enum definitions in output
--no-relationships Skip relationship lines in output
--format FMT [FMT ...]
Output format(s): plantuml (.puml), mermaid (.mmd),
json (.json), html (.html). Default: plantuml. With -o
the extension is set per format; multiple formats
require -o, e.g. --format plantuml mermaid
--inject FILE Inject the diagram into a markdown file between '<!--
erdify:start -->' and '<!-- erdify:end -->' markers
(only that region is rewritten). Uses a single
--format (default mermaid). Combine with --check to
fail on drift, e.g. --inject README.md
--check Don't write; exit non-zero if the --output file is
missing or differs from the freshly generated diagram
(for CI / pre-commit drift checks)
-v, --version show program's version number and exit
Example: erdify ./src/database -o database_erd.puml
The block above is generated from
erdify --help; runpython scripts/gen_cli_docs.pyafter changing CLI flags.
Configuration via pyproject.toml¶
Instead of passing flags every time, commit them under [tool.erdify] in your
project's pyproject.toml. erdify searches upward from the input directory for
the nearest pyproject.toml and reads that table.
[tool.erdify]
title = "My Database Schema"
output = "docs/database_erd" # relative paths resolve from the project root
format = ["plantuml", "mermaid"] # one or both
sources = ["django"]
exclude = ["audit_log", "*Link"]
exclude_paths = ["migrations", "legacy"]
infer_keys = true
django_raw_types = false
sql_dialect = "postgres" # required for CREATE TYPE … AS ENUM support
With that in place, erdify . uses these settings. Precedence is explicit CLI
flag > [tool.erdify] value > built-in default. (Boolean flags merge by OR: a
flag enabled in config can be added to on the CLI but not turned off there.)
Keeping the diagram in sync (--check)¶
--check regenerates the diagram in memory and compares it to the existing
--output file or the injected region in an --inject target without writing.
It exits 0 when the content is up to date and non-zero when the file is missing
or stale — ideal for CI or a pre-commit hook.
erdify ./src/database -o docs/erd.puml --check
erdify ./src/database --inject README.md --check
Running as Module¶
python -m erdify ./src/database -o erd.puml
Python API¶
from pathlib import Path
from erdify import parse_models_directory, generate_plantuml
# Parse Python models
entities, enums = parse_models_directory(Path("./src/database"))
# Parse SQL DDL (requires erdify[sql])
entities, enums = parse_models_directory(Path("schema.sql"), sql_dialect="postgres")
# Generate PlantUML
diagram = generate_plantuml(
entities=entities,
enums=enums,
title="My Database ERD"
)
# Save or use the diagram
Path("erd.puml").write_text(diagram)
parse_models_directory accepts both a Python models directory and a .sql file
(or a directory scanned with --include '*.sql'). For Python models only, the
lower-level ASTDatabaseParser class is also available — it does not handle .sql
input, so use parse_models_directory when working with SQL DDL.
Programmatic Access¶
For lower-level control, use the parser and generator classes directly:
from erdify import (
ASTDatabaseParser,
PlantUMLGenerator,
EntityInfo,
FieldInfo,
EnumInfo,
)
# Low-level parser access (Python models only — use parse_models_directory for .sql)
parser = ASTDatabaseParser(Path("./models"))
entities, enums = parser.parse_all_models()
# Access entity details
for name, entity in entities.items():
print(f"Table: {entity.table_name}")
for field in entity.fields:
if field.is_primary_key:
print(f" PK: {field.name}")
elif field.is_foreign_key:
print(f" FK: {field.name} -> {field.foreign_table}")
# Custom generator with options
generator = PlantUMLGenerator(
entities=entities,
enums=enums,
title="Custom ERD"
)
output = generator.generate()