尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Interactive HTML explorer for PostgreSQL data models. A self-contained page generated from a DDL file
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Turn a SQL data model into one self-contained HTML page you can open, share
and explore: an overview of every table, click one to isolate it with its
relations, field-level detail, search. No server, no build step, no
dependencies — the page opens straight from file://.
Try it on mcdview.dev (drop a .sql/.dbm, get a
shareable link) · Live demo ·
Example diagrams · Blog
*Overview → rearrange → click a table to isolate it with its related tables →
search. Open the live, interactive version.*
The same tool renders a model right here檢視完整 README ↗Turn a SQL data model into one self-contained HTML page you can open, share
and explore: an overview of every table, click one to isolate it with its
relations, field-level detail, search. No server, no build step, no
dependencies — the page opens straight from file://.
Try it on mcdview.dev (drop a .sql/.dbm, get a
shareable link) · Live demo ·
Example diagrams · Blog
Overview → rearrange → click a table to isolate it with its related tables → search. Open the live, interactive version.
mcdview model.sql --to-mermaid emits a Mermaid erDiagram that GitHub and
GitLab draw natively — no image, no hosting:
erDiagram
categorie {
serial id PK
text nom
text slug
}
produit {
serial id PK
text nom
bigint prix
integer categorie_id FK
text sku
}
client {
serial id PK
text nom
text email
text telephone
}
commande {
serial id PK
integer client_id FK
date passee_le
bigint total
text statut
}
ligne {
serial id PK
integer commande_id FK
integer produit_id FK
integer quantite
numeric remise
}
avis {
serial id PK
integer produit_id FK
integer client_id FK
integer note
text commentaire
}
categorie ||--o{ produit : ""
client ||--o{ commande : ""
commande ||--o{ ligne : ""
produit ||--o{ ligne : ""
produit ||--o{ avis : ""
client ||--o{ avis : ""
#schema.table permalinks, keyboard shortcuts (/ search, r rearrange,
Esc overview). One HTML file, works offline..dbm, dbdiagram.io .dbml, Prisma, MySQL Workbench .mwb,
Rails db/schema.rb, Mermaid erDiagram, Drizzle schema.ts.--diff old colors what was added, removed and
changed (tables, columns, foreign keys, indexes), detects renames, and can
write a JSON summary (see below).--to-mermaid for a diagram that renders in any
Markdown file.--db postgresql://… / mysql://… reads a running
schema (CLI only).mcdview new.sql --diff old.sql — added tables/columns/FKs in green, removed
in red (kept, struck through), changed in amber, with a legend and a "show
only what moved" filter:
pipx install mcdview # the CLI, isolated
pipx install "mcdview[dialects]" # + sqlglot for MySQL/SQLite/… input
Or run the script straight from a checkout — it has no dependency of its own:
./mcdview.py model.sql. The .dbm/.dbml/.prisma inputs still need their
external converter in the PATH (see Dialects).
mcdview model.sql # (or ./mcdview.py from a checkout)
./mcdview.py model.sql
./mcdview.py model.sql -o explorer.html --titre "My project"
./mcdview.py model.dbm # pgModeler model (needs pgmodeler-cli)
./mcdview.py model.dbml # dbdiagram.io model (needs @dbml/cli)
./mcdview.py schema.prisma # Prisma schema (needs prisma)
./mcdview.py model.mwb # MySQL Workbench model (native, no tool)
./mcdview.py db/schema.rb # Rails schema (native, no tool)
./mcdview.py diagram.mmd # Mermaid erDiagram (native, .mmd/.md)
./mcdview.py schema.ts # Drizzle ORM schema (native, no tool)
./mcdview.py --db postgresql://user:pw@host/db # dump a live database (CLI only)
./mcdview.py new.sql --diff old.sql # compare two versions of a model
Then open the generated HTML file in a browser.
--diff BASELINE compares the main model against an older one (each may be
any supported format) and colors the result: tables, columns and foreign keys
that were added show green, removed ones red and struck through
(kept on the diagram so you can see what went), changed ones amber. A
legend appears at the bottom with per-category counts and a "N touched"
button that hides the unchanged tables to frame just what moved. Handy for
reviewing a migration before running it.
--db reads the schema straight from a running database instead of a file:
postgresql://… shells out to pg_dump -s, mysql://… to mysqldump --no-data. It is a command-line-only feature — never wire it behind a
public service, since it would let a caller point the process at any host it
can reach (SSRF).
A .dbm input needs pgmodeler-cli in the PATH: mcdview delegates the
SQL generation to it (pgModeler resolves its relationships at export time),
and reuses the table positions drawn in the model.
In the page:
#schema.table
permalink that reopens straight on that table;| Option | Effect |
|---|---|
-o, --sortie FILE | Output HTML file (default: <sql>.html) |
--titre TEXT | Title shown in the page (default: file name) |
--dbm FILE | Reuse table positions from a pgModeler model instead of automatic layout |
--fk-audit REGEX | Tag as "audit" the FKs whose constraint name matches: hidden by default, shown back with a checkbox |
--lang {fr,en} | Language of the page UI (default: fr) |
--dialect NAME | Input SQL dialect (default: auto); non-PostgreSQL needs sqlglot |
--home-url URL | Wrap the header logo in a link to this URL |
--logo FILE | Replace the header logo with this image (svg/png/jpg…, shown 22×22) |
--credit TEXT | Attribution badge text, bottom-right; defaults to mcdview (linking mcdview.dev) unless --no-credit |
--credit-url URL | Make the --credit badge a link to this URL |
--no-credit | Do not place the attribution badge |
--db URL | Read a live database's schema instead of a file (postgresql://… via pg_dump, mysql://… via mysqldump); CLI only |
--diff BASELINE | Compare against an older model (any supported format); added/removed/changed tables, columns and FKs are colored |
--summary FILE | With --diff: also write a JSON summary of the changes (counts + change list) to FILE |
--to-mermaid | Output a Mermaid erDiagram (paste in a .md; GitHub/GitLab render it) instead of the HTML page |
--to-dico | Output a Markdown data dictionary (one section per table: column / type / key) instead of the HTML page |
--to-preview |
Without --dbm, mcdview computes an automatic layout: one zone per schema,
tables arranged in balanced columns, related tables pulled together.
PostgreSQL uses the built-in parser (no dependency). For any other dialect,
pip install sqlglot and mcdview reads it — MySQL/MariaDB, SQLite, SQL Server
(tsql), Oracle, DuckDB, Snowflake, BigQuery, Redshift, ClickHouse, Trino,
Spark, Hive. --dialect auto (the default) uses the PostgreSQL parser first
and, when it finds no table, tries several sqlglot dialects and keeps the one
that parses the most tables; pass --dialect mysql (etc.) to force one. Model files are read through an upstream converter (an optional dependency,
like the SQL dialects): pgModeler .dbm via pgmodeler-cli,
dbdiagram.io .dbml via @dbml/cli, and Prisma schema.prisma via the
prisma CLI. MySQL Workbench .mwb, Rails db/schema.rb, Mermaid erDiagram
(.mmd/.mermaid/.md) and Drizzle ORM schema.ts are read natively
(no external tool needed). Other proprietary formats (Navicat,
ERwin, Oracle SQL Developer Data Modeler…) have no reliable converter: export
their SQL instead (Workbench-style Forward Engineer), which mcdview reads.
--fk-audit is for models where every table carries audit columns
(created_by, modified_by...) pointing to a users table: those FKs turn
that table into a hub linked to everything and clutter the graph.
CREATE TABLE [schema.]table (...): columns, types, NOT NULL, DEFAULT
(tables without an explicit schema go to public);CONSTRAINT ... PRIMARY KEY) or added afterwards
(ALTER TABLE ... ADD CONSTRAINT ... PRIMARY KEY, pg_dump -s style);ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ... REFERENCES ...,
including composite keys and targets without an explicit column list
(resolved against the target's primary key);PARTITION OF, ATTACH PARTITION): hidden from the diagram,
their constraints are carried back to the parent table;COMMENT ON TABLE and COMMENT ON COLUMN.A pg_dump -s dump works as is. Views, functions and data are ignored.
mcdview prints machine-readable output and sets an exit code, so it fits a pipeline with no browser:
mcdview schema.sql --lint --fail-on warning checks the
model against rules (missing primary key, unindexed foreign key, naming) and
exits non-zero on a violation of that severity or worse. Use --diagnose for
a JSON status that never fails when you only want a report.--to-mermaid writes a Mermaid erDiagram for a
Markdown page, --to-dico a Markdown data dictionary, --to-preview a static
SVG card. Commit them or attach them to a release.To publish to the hosted instance (mcdview.dev) from CI — push a schema, get a shareable link back — two integrations are maintained in their own repositories:
Gheop/mcdview-action:
uses: Gheop/mcdview-action@v1gitlab.com/Gheop/mcdview:
include: component: gitlab.com/Gheop/mcdview/mcdview@~latestEach example ships as a .sql in exemples/; the browsable pages are
rebuilt by CI on every push:
| Model | Contents | Source | |
|---|---|---|---|
| Médiathèque — fictional French library, shows schemas zones, comments and audit FKs | open | 12 tables, 3 schemas, 21 FKs | mediatheque.sql |
Pagila — DVD rental store (the PostgreSQL classic), with a partitioned payment table | open | 16 tables, 22 FKs | Pagila (BSD) |
| Northwind — trading company, the historic Microsoft sample | open | 14 tables, 13 FKs | northwind_psql |
| Chinook — digital music store | open | 11 tables, 11 FKs | chinook-database (MIT) |
The real-world schemas are trimmed to their DDL (no data); each file keeps its source and license in a header comment. To regenerate, e.g.:
./mcdview.py exemples/mediatheque.sql --titre "Médiathèque (démo)" --fk-audit '_idmodificateur_fk$' --lang en
./mcdview.py exemples/pagila.sql --titre "Pagila (DVD rental)" --lang en
Plain Python 3, no dependency. All the rendering lives in
templates/explorateur.html (inline CSS/JS); the data is injected as JSON
in place of __DONNEES__.
The harness under tests/ last ran mcdview over 13,408 model files:
9,913 .sql plus native .ts (Drizzle), Mermaid, Rails schema.rb and
MySQL Workbench .mwb, harvested from public GitHub repositories, plus
synthetic models up to 5000 tables. Results: zero crashes and zero
timeouts (2 s per-file budget). Every loadable schema produced a valid
page (DOM-verified on a sample in headless Chrome); MySQL and SQLite .sql
inputs are detected and get a clear hint. Median page build: 3 ms; worst
case (a 5.7 MB model): 1.3 s. Separately, pgModeler .dbm models convert
through pgModeler's CLI in a frozen-image CI job (a --fix-model repair
pass catches models saved by older versions).
Model data (names, types, comments, defaults) is HTML-escaped and the JSON
data island escapes every <, so a hostile schema cannot inject markup or
script into the page — this matters when generating pages from files you did
not write. tests/test_securite.py checks the escaping and a ReDoS/DoS time
budget on hostile inputs (tests/malveillant/).
tests/tester.py runs mcdview end-to-end on every committed example and
every pgModeler sample model, checks pinned table/FK counts and times each
run; tests/grand_banc.py runs the whole local corpus (--strict fails on
any exception, --dbm adds the pgModeler models, --chrome N DOM-validates
N sampled pages); tests/rapatrier.sh, tests/moissonner.py and
tests/generer_synthetique.py fill the local, uncommitted corpus.
tests/test_dialectes.py parses committed non-PostgreSQL fixtures, including
tests/dialectes/boutique.mariadb.sql — a frozen mysqldump --no-data dump
(backtick quoting, named inline CONSTRAINT FKs, a composite primary key)
that pins the exact SQL a --db mysql://… run feeds the parser, so the
--db path stays covered without a live server. The pre-commit hook
(git config core.hooksPath .githooks) runs the pinned regression, the
security suite and the strict corpus campaign.
MIT. The example schemas keep their own licenses, noted in each file's header.
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2026-09-01 | Initialize; add a CI section (local flags + hosted GitHub/GitLab integrations), document --to-dico/--to-preview/--lint/--fail-on, add the blog link, reconcile the tested-at-scale figure |
--lint sees the indexes it used to miss (2026-09-27)--lint flagged foreign keys as unindexed_fk although an index covered
them, because some declared indexes were not read. They now are: Rails
t.index and add_index; Drizzle index(), uniqueIndex() and unique()
with .on() or .onOnly(), and column-level .unique(); SQL UNIQUE inside
CREATE TABLE (column or table level); MySQL KEY / INDEX inside
CREATE TABLE, which mysqldump writes for every foreign key. Across the test
corpus (13,630 files, 94,146 FKs), unindexed_fk drops from 64,806 to 44,172:
Rails 6,849 → 232, Drizzle 15,273 → 7,853, MySQL 8,005 → 2,531.ALTER TABLE t ADD PRIMARY KEY (id), ADD KEY k (col)), lost both: nearly
every table was reported as missing_pk. They are read now; across the
corpus missing_pk drops from 20,820 to 8,505.primaryKey({ columns: [...] }) and the older
primaryKey(t.a, t.b)) are read.cascade from { onDelete: "cascade" }
or number from { mode: "number" }. It now takes its field name
(2,613 columns fixed in the corpus).pgTable( calls could take minutes to
parse (3 min for 130 KB). Parsing is now linear in the file size.--dialect auto now chooses the dialect on the whole file. On files over
25 KB it used to decide on the first 25 KB, cut mid-statement, and could pick
the wrong one: tables went missing (some MySQL dumps showed none at all) and
column types were rewritten (VARCHAR(191) shown as text(191), BOOLEAN
as integer). Across the test corpus, 36 files regain 2,406 tables and none
loses any.[word] word inside a comment is no longer taken
for SQL Server.mysql or sqlite provider is parsed straight in that
dialect instead of trying up to seven in turn: about 100 ms less per run.--dialect mysql (or sqlite) to skip the dialect trial.ON DELETE / ON UPDATE) are now parsed and shown when
the model declares them, from PostgreSQL, the sqlglot dialects, MySQL
Workbench .mwb, and Rails add_foreign_key.--logo on a white-label page — with no
network request and no /favicon.ico 404, even opened offline..dbm (valid XML but unexpected structure) no longer crashes page
generation while reading table positions; such a table falls back to the
automatic layout.prefers-reduced-motion.prefers-reduced-motion: the motion is dropped for
viewers who ask their OS for reduced motion.0..1) when it is nullable. Join tables
read as N-N through their two links. Off by default; hovering or isolating a
table turns its markers blue and shows a short label (*, 1, 0..1) at each
end. The link now leaves the tip of the marker. The SVG export includes the
markers when they are on. Added a regression test (tests/test_cardinalites.py).etabli →
etablissement, etablissementindividu, etablissementtelephone) now lists
all the matching tables. The search datalist put each table's columns right
after it, so one table's columns crowded its siblings out of the browser's
suggestion popup. All table names are now inserted before any column name.mcdview stamp (linking mcdview.dev) is now on by default on
every page, not only branded ones. --no-credit removes it; --credit TEXT
sets a custom label. composer_page gains a tampon parameter (default on) so
a caller that already shows mcdview's branding can drop the stamp. The
published example pages set --no-credit (they are the official showcase).tests/test_export_html.py).prisma migrate diff refused now convert. The schema is
preprocessed first, without changing the tables, columns or foreign keys read
from it: @id is dropped from view blocks (Prisma forbids a primary key on
a view), a missing datasource url is filled in (the diff never connects),
and wrong-provider native types (@db.Int in a postgresql schema) are
stripped. Added an edge-case fixture and a preprocessing test.tests/test_undo.py).db/schema.rb written with the old hashrocket option syntax
(create_table "x", :id => false) no longer gets a phantom id primary key
on its id: false tables. The native parser only recognised the modern hash
form (id: false); it now reads both, so schemas from before ~2012 (and their
join tables) come out right. Added a legacy fixture and test.tests/test_panneau.py).reports_to) now draws a small loop on
the table's corner, so the hierarchy is visible — the old routing collapsed it
to an invisible point.tests/test_liens.py).#hud label { display: flex } rule overrode the hidden attribute, so the
checkbox showed even with nothing to toggle.tests/test_positions.py).--logo or --home-url) now carries a discreet clickable
mcdview badge by default, linking to https://mcdview.dev. Branding drops the
header link back to mcdview, so the badge keeps the attribution. An explicit
--credit still sets its own text and url; a plain, unbranded page stays bare.--no-credit opts out of the badge, even on a branded page.--to-dico data dictionary on the CLI (2026-08-30)--to-dico outputs a Markdown data dictionary (one ## schema.table section
with a column / type / key table) instead of the HTML page — to -o if
given, else stdout. Same content as the in-page export → Markdown, now
scriptable for a docs/CI pipeline like --to-mermaid and --to-preview.CREATE TABLE whose ( is
followed by columns on the same line and whose body continues on later lines
(closing ) elsewhere) — e.g. CREATE TABLE t (id int,\n FOREIGN KEY …\n);.
Previously it sat between the two fast passes and was silently dropped in a
mixed file (only rescued by sqlglot when the whole file had zero
regex-parseable tables). The single-line pass now extends to the statement's
closing ); within a bounded window (a C-level search, no copy), so the
ReDoS/DoS budget is unchanged (the orphan-openers stress stays ~0.4 s).--to-preview emits a static SVG snapshot of the diagram (auto-layout,
schema-colored headers, columns, FK links) — a social/OpenGraph card image.?focus=<table> isolates a table, theme=dark|light forces the theme,
audit=show reveals audit FKs, and hubs / cycles open on that analysis —
so a precise view can be embedded in a doc.--lint checks the schema against rules (missing primary key, unindexed
foreign key, disconnected table, non-lower_snake_case names, FK without a
target) and prints JSON violations (rule, table, column, severity);
--fail-on error|warning|info turns it into a CI gate.window.load and
by the safety timeout (which now re-fits, not just reveals), and it is skipped
once the viewer has panned or zoomed, so it never resets a view in use.⬇ export dropdown
to declutter the toolbar.⇢ jointure): pick two tables and mcdview highlights the
shortest foreign-key path between them and writes the SELECT … JOIN … ON …
skeleton (copy button included) — the "how do I join these?" answer.↻ cycles): highlight tables sitting on a circular foreign-key
dependency (Tarjan SCC), including self-references — a schema smell that
breaks insert ordering and dumps.◉ hubs): shade every table by its number of FK relations,
so the central hub tables stand out at a glance, with a degree badge.∑ résumé): tables, FKs, schemas, average columns, the
most-referenced table, orphan tables (no FK) and how many sit on a cycle.type:<sql type> highlights every table with a column
of that type, ref:<table> highlights the tables that reference it, and a
plain query now falls back to a fuzzy (subsequence) name match.⬇ MD) and a Graphviz DOT
graph (⬇ DOT), alongside the existing SVG export.CREATE TABLE
(columns, primary key, foreign keys) to the clipboard.≈ FK ?): flags <x>_id columns with no declared
foreign key when a table named <x> exists — a heuristic hint to review.CREATE TABLE body are now detected: a
column-level inline col int REFERENCES other(id), a table-level
FOREIGN KEY (col) REFERENCES other(id) (single or composite), a column-less
REFERENCES other that leans on the target's primary key, and
self-references. Previously only ALTER TABLE ... ADD ... FOREIGN KEY
(pg_dump style) was read, so hand-written schemas showed 0 FKs and every
table floated unlinked. The sqlglot path already handled these; this fixes
the built-in PostgreSQL parser.--diagnose gained a soft disconnected_tables anomaly (several tables and
not one FK), which is almost always a parser gap rather than a real model.,\n col TYPE, common in hand-written schemas) now
parses: the comma leading each entry no longer hides the column, its
primary key, or a table-level foreign key.REFERENCES column from a wrapped FK, and
several sqlglot AST edge cases (exotic defaults, constraint/comment/index
nodes) — plus a safety net so no sqlglot AST shape can crash the tool.CREATE TABLE t (a int);.--dialect auto on large non-PostgreSQL files (dialect picked on a
prefix, ~4–6× less parse time).pgTableCreator factories are supported.--diagnose prints a JSON verdict (status, dialect, counts, anomalies) and
never fails — for a hosting service to flag problematic uploads.CREATE TABLE t (a int, b numeric(10,2)); (no newline after the open paren),
not only the pg_dump (\n layout. Before, such DDL only parsed when
sqlglot was installed. Body splitting is depth- and string-aware, so a comma
or paren inside a type or a 'literal' never splits a column; still linear,
still within the DoS budget.--version prints the installed version.--db is now covered end-to-end in CI (against a throwaway PostgreSQL
service), not only manually.CREATE [UNIQUE] INDEX, ALTER … ADD CONSTRAINT … UNIQUE, inline UNIQUE).
Previously only the built-in PostgreSQL parser read them, so a single-line
CREATE TABLE … (which routes to sqlglot) reported no index changes in a
diff. MySQL UNIQUE KEY is picked up as a bonus.pipx install mcdview (extra [dialects] pulls in
sqlglot). The HTML template and logo ride along as bundled data; running the
script straight from a checkout keeps working unchanged. Releases publish
automatically on a version tag via PyPI Trusted Publishing (no stored token).mcdview a.sql b.sql),
cross-file foreign keys resolved./, r, Esc), and
--watch to regenerate the page on every save.CREATE [UNIQUE] INDEX, ADD CONSTRAINT … UNIQUE) are parsed and shown in the detail panel..dbm was injected into the page
unescaped — a hostile model could run script in a viewer's browser. The
color is now escaped like all other model data (and ech() now escapes
single quotes too, closing attribute-breakout)..mmd took ~18 s); both now use
a bounded string search, and the DoS-budget test covers every parser, not
just PostgreSQL.DEFAULT 'PRIMARY KEY', a CHECK or an inline comment
mentioning the words no longer marks a column as a primary key (regression
from the inline-PK support).url_sure now strips tab/newline/control chars before the
scheme check (java\tscript: is neutralized); the XML DTD guard scans the
whole document; malformed .mwb/.dbm inputs exit cleanly instead of
dumping a traceback.nouvelle_fk factory joins nouvelle_table/nouvelle_colonne;
new tests/test_parser.py; dead code removed.id serial PRIMARY KEY), not only a separate PRIMARY KEY (...) line or
an ALTER TABLE. The column gets its 🔑 and the constraint no longer leaks
into the displayed type.--to-mermaid renders the model as a Mermaid erDiagram. Pasted into a
Markdown file, GitHub and GitLab render it natively — a static diagram in
the README, no hosting needed (the interactive page stays the way to explore
a big model). See docs/diagrams.md for the four examples.old → new (the old
type struck through).renamed_from.table.column or a bare column name):
it isolates the table and highlights the row.--summary FILE (with --diff) writes a machine-readable JSON summary of
the changes: per-category counts (tables/columns/FKs added, removed,
changed) and the change list, with the previous type kept for retyped
columns ("was": "numeric(10,2)"). Lets a caller show change badges or a
version timeline without parsing the HTML.--diff BASELINE compares the model against an older version (any supported
format on either side) and colors the diagram: tables, columns and foreign
keys that were added (green), removed (red, struck through, kept on the
diagram), or changed (amber). A legend shows the key. Useful to review a
migration visually before applying it.charger() dispatch and the
nouvelle_table / nouvelle_colonne factories, so every format flows
through the same code — which is what makes the diff work across all of them..mwb, .dbm) is refused if it declares a DTD or entities, the
vector for entity-expansion ("billion laughs") and XXE attacks the stdlib
XML parser does not block on its own..mwb archive is read through a size cap, so a tiny file cannot
decompress into gigabytes (zip bomb).pgmodeler-cli, dbml2sql, prisma,
pg_dump/mysqldump) runs under a timeout and is killed if it hangs.tests/test_securite.py covers all four (generated on the fly, like the
ReDoS bombs). This matters for a service that renders files it did not write.o{, }o) is no longer mistaken for an entity
block, which previously invented a phantom one-letter table.int id PK "SERIAL") become column comments, shown in
the detail panel; %% comment lines and a direction directive inside an
entity block are ignored instead of read as columns; comma-separated
attribute keys (PK, FK) are accepted..mmd and inside Markdown
fences): 918 tables, 1002 FKs, zero bogus columns.--db postgresql://… / --db mysql://…: dump a running database's schema
(pg_dump -s for PostgreSQL, mysqldump --no-data for MySQL/MariaDB) and
render it, no intermediate file needed. The positional model argument
becomes optional; the page title defaults to the database name.MYSQL_PWD environment variable, never on
the process command line.CONSTRAINT node), so --fk-audit works on MySQL and
MariaDB models too.schema.ts natively: each pgTable/mysqlTable/
sqliteTable becomes a table, its type("col") fields columns (with
.primaryKey()/.notNull()), and .references(() => t.col) the foreign
keys; commented-out definitions are ignorederDiagram natively, raw .mmd/.mermaid or inside a
```mermaid fence in a .md: entities become tables, attributes
columns (PK marker → key), each relationship an FK from the crow's-foot
("many") side to the "one" sidedb/schema.rb natively (the create_table / add_foreign_key
DSL is regular): the implicit id primary key, column types, and foreign
keys (default column resolved by singularizing the target table).mwb models natively — the file is a zip whose
document.mwb.xml (GRT object tree) is parsed with the standard library,
no external tool: schemas, tables, column types, primary and foreign keysschema.prisma models, converted to SQL by prisma migrate diff; the schema's provider (postgres/mysql/sqlite/sqlserver) is detected
automatically, MongoDB schemas are reported as unsupportedCONSTRAINT "x_pkey" PRIMARY KEY ...), as emitted by Prisma and modern tools.dbml models (converted to SQL by @dbml/cli), the
same upstream-converter pattern as .dbmADD FOREIGN KEY ...
without CONSTRAINT name), which dbml2sql and some dumps emit--credit TEXT / --credit-url URL: a slanted rubber-stamp attribution
badge (mcdview logo + text) in the bottom-right corner, off by default;
text escaped, optional link--home-url and --credit-url now reject dangerous URL schemes
(javascript:, data:…), keeping only http(s)/mailto/relative links[bracket] identifiers) is routed to the sqlglot tsql
parser instead of being mangled by the PostgreSQL parserALTER TABLE ... ADD [COLUMN] name type columns are now read, not just
the ones inside the CREATE TABLE bodyPLAYERID primary key on a
playerID column shows its 🔑 instead of being dropped as a phantom —
found by the content-invariant test on a wider harvested corpus--home-url URL: the header logo becomes a link (e.g. back to the
hosting site); URL escaped, nothing changes when the option is absent--logo FILE: replace the header logo with your own image (svg/png/jpg…),
embedded as an <img> data URI so a third-party SVG cannot run scripts`id` or
"timestamp" primary key no longer becomes a phantom (unmatched) keyCREATE TABLE "accounts"), so double-quoted
DDL (e.g. Drizzle output) is parsed instead of dropped entirelytests/test_invariants.py: checks the parsed model is internally
consistent (no empty types, no phantom PK columns, FK endpoints exist)--dialect auto now tries several sqlglot
dialects and keeps the one parsing the most tables, instead of guessing a
single one — recovers files that were mis-detected (a 28-table model was
read as the wrong dialect and dropped entirely)12 tables · 21 FK · mysql)INT(11) → int(11)), keeping string literals intactsqlglot backend (PostgreSQL stays dependency-free); --dialect flag,
auto sniffs and falls back. On the harvested corpus, files that produced
no page dropped from 257 to 18tests/test_dialectes.py), sqlglot wired into
CI and the pre-commit hook.sql or .dbm and get a shareable link, no install neededdocker/pgmodeler-cli/ + image.yml build and publish
ghcr.io/gheop/pgmodeler-cli (Fedora 44 + pgModeler 1.2.2, plus a -node
variant for container: jobs); the tag is the pgModeler version baked in.dbm job now runs inside that pinned image (fixed version → stable
counts) and is blocking instead of best-effort--fix-model on pgmodeler-cli 1.2.2 writes the repaired .dbm in full,
then segfaults while freeing the model (memory-layout dependent, systematic
in containers). mcdview now judges the repair by the output file, not the
exit code, so old .dbm models convert inside a containerruff --select F,E9, py_compile), the pinned regression, the security
suite, the strict corpus campaign, HTML structure validation and a
headless-Chrome DOM check on the generated example pages; deploy to Pages
only runs on main after the tests passtests/valider_html.py validates a page's structure and data island.dbm job installs pgmodeler-cli on the runner (never
blocks a PR)#schema.table permalinks that
reopen on the right table; DEFAULT values in the detail panel; table
comments as tooltips; a table/FK counter in the toolbar<, closing an XSS vector; the CREATE TABLE body is now bounded
by string search instead of a lazy regex, killing a ReDoS (a 830 KiB
malformed file went from 13 s to 0.3 s).dbm (saved by an older pgModeler), mcdview
now retries through --fix-model before giving up — on the harvested
corpus this takes the refusal rate from 136/296 down to 2/296tests/moissonner.py, tests/grand_banc.py):
hundreds of real-world schemas harvested from GitHub plus synthetic
models up to 5000 tables, per-phase timings and DOM validationtests/tester.py) over the examples, the
pgModeler sample models and an optional local corpus of big real-world
schemas (GitLab: 1066 tables parsed in ~0.7 s), plus a pre-commit hook.dbm pgModeler model can be passed directly as input: the SQL is
produced by pgmodeler-cli and the table positions drawn in the model
are reusedpublic
schema), an opening parenthesis on its own line, primary keys declared
via ALTER TABLE (pg_dump -s style), composite foreign keys, FK targets
without a column list, and partitioned tables (partitions are folded into
their parent)--lang {fr,en} option: language of the generated page's interface
(search box, help text, detail panel labels)exemples/mediatheque.sql) with a live version
on GitHub Pages.dbm becomes optional--titre, --fk-audit, --dbm, -o options| Output a static SVG snapshot of the diagram (a social / OpenGraph card) instead of the HTML page |
--watch | Regenerate the page whenever the input file changes (Ctrl-C to stop); file input only |
--diagnose | Print a JSON diagnosis of the input (status ok/no_table/anomaly/error, dialect, counts, anomalies) instead of a page; exits 0 even on failure |
--lint | Check the schema against rules (missing PK, unindexed FK, naming…) and print JSON violations instead of a page — a finer CI gate than --diagnose |
--fail-on {error,warning,info} | With --lint, exit non-zero when a violation of at least this severity is found |