One static binary. Run remus, answer four questions, and get Mermaid, DBML, SQL DDL and JSON — with enums, domains, partitions, row level security and generated columns kept intact instead of flattened into generic boxes.
$ remus
remusyour Postgres schema, as text? Database postgres://localhost/app
✓ app · 14 tables, 2 views
? Schemas public
? Formats mermaid, sql, dbml, json
? Diagram physical
? Folder schema
✓ schema/schema.mmd 2.1 kB
✓ schema/schema.sql 8.4 kB
✓ schema/schema.dbml 4.6 kB
✓ schema/schema.json 36.0 kB
next time, in one line:remus -u "$DATABASE_URL" -f json,mermaid,dbml,sql --out-dir schema
no questions asked
# one format to stdout$ remus -u postgres://localhost/app > docs/schema.mmd
# junction tables collapsed into many-to-many, no columns$ remus -u postgres://localhost/app --conceptual --no-attributes
# credential-free: remus never sees your connection string$ remus --print-sql | psql "$DATABASE_URL" -Atf - > schema.json
$ remus -i schema.json -f all --out-dir docs/schema
One schema, four outputs
A small blog schema, run through remus. Everything below is the tool's actual output for the input in the first tab; the diagram is rendered live from the Mermaid text.
examples/blog/schema.sql
The input: six tables, an enum, a self-referencing foreign key, a pure junction table and a view. Small enough to read, varied enough to show what each format keeps.
drag to pan · ⌘/ctrl + scroll to zoom · double-click to zoom in
Crow's feet are what the catalog proves: users |o--o{ comments because author_id is nullable, users ||--o| profiles because the foreign key is also the primary key. Switch to --conceptual and post_tags becomes a single many-to-many edge.
schema.dbml
Paste into dbdiagram.io, DrawSQL or ChartDB. Enums become Enum blocks the editor links to; what DBML cannot express (check constraints, partial indexes, RLS) survives as notes.
schema.sql
Dependency-ordered DDL that replays into an empty database. Foreign keys come as ALTER TABLE after every table exists; views after what they read. Not pg_dump, and the header says exactly what it leaves out.
schema.json
The model itself, and the only lossless format. Codes are PostgreSQL's own ("kind": "r" is a table, "on_delete": "c" cascade), so a payload produced by running the SQL in psql needs no translation.
Built for Postgres, not for "SQL"
Most diagram tools treat Postgres as generic SQL. remus models what the catalog actually says.
Native types, first-class
Enums, domains with their base type, composite types, arrays of any of them. Identity and generated columns, partitioned tables as one box with their partitions listed, views with what they read, RLS policies with their roles.
Credential-free by design
--print-sql prints the one query remus runs. It reads pg_catalog only, never information_schema, never a row of your data. Run it yourself in psql and pipe the JSON back with --input -.
Honest cardinality
Only what the catalog can prove. Nullability decides whether a child must have a parent; uniqueness decides whether a parent has at most one child. Nothing is guessed.
Conceptual mode
--conceptual recognises pure association tables, exactly two foreign keys and nothing of their own, and draws one N:N edge in their place. The step from a physical schema toward an actual data model, and the only heuristic in the tool.
Unix-shaped
Reads a URL or stdin, writes stdout or files, exits non-zero with a cause chain when something is wrong. Drop it in CI and diff schema.sql in every pull request.
One query, one model
Every format is a pure function of the same JSON. Introspect once, render four times. The query pins its own search_path, so two people get byte-identical output from the same database.
What each format keeps
JSON is authoritative. SQL covers everything the model carries. The diagram formats are lossy by nature, and this table is the contract.
Feature
JSON
SQL
DBML
Mermaid
Tables, columns, keys
✓
✓
✓
✓
Cardinality
✓
n/a
✓
✓
FK actions, deferrable
✓
✓
delete / update
✗
Check & exclusion constraints
✓
✓
note
✗
Enums
✓
✓
✓ Enum block
name + note
Domains, composite types
✓
✓
name + note
name + note
Identity, serial
✓
✓
✓ increment
note
Generated columns, defaults
✓
✓
note / ✓
✗
Indexes, partial predicates
✓
✓
✓ / note
✗
Partitioning
✓
✓
parent, key in note
parent only
Views, materialized views
✓
✓
✗
opt-in, as edges
Row level security
✓
✓
note
✗
Comments
✓
✓
✓
columns only
How it works
1
One query
A single statement against pg_catalog returns the whole schema as one JSON document. It is embedded in the binary and printed verbatim by --print-sql, so you can read it, audit it, or run it without remus at all.
2
One model
That JSON is the model. Tables, columns, constraints, indexes, policies, enums, domains, composites, partitions, extensions, in the catalog's own vocabulary. Nothing physical that would differ between two restores of the same schema.
3
Pure emitters
Mermaid, DBML and SQL are rendered from the model with no I/O and no database in sight. That is what makes the outputs reproducible, golden-file tested, and identical whether they come from the CLI or, later, a browser.
credential-free
$ remus --print-sql > introspect.sql # read it; it is 280 lines of pg_catalog$ psql "$DATABASE_URL" -Atf introspect.sql > schema.json
$ remus --input schema.json --format all --out-dir docs/schema
Where it fits
pgAdmin generates an ERD from a live database. pgModeler is a mature, Postgres-native desktop modeller with reverse engineering, diff and sync. Both are better places to draw. remus is the Unix-shaped complement: text out, pipes in, runs in CI, and produces the formats those editors, GitHub and Miro already consume.