Global options (before the subcommand):
| Option | Description |
|---|---|
-c, --config <FILE> |
Optional TOML config; merges with flags (see Configuration) |
--color auto|always|never |
Terminal styling |
-v, --verbose |
More log output (repeatable: -v info, -vv debug, -vvv trace with span events) |
-q, --quiet |
Suppresses non-error diagnostics (warning/info/hint) and success notices; errors are still reported |
Logging is filtered through RUST_LOG. When RUST_LOG is set to a non-empty
value it takes precedence and fully controls per-target filtering (standard
tracing EnvFilter
syntax), so you can trace a single module, e.g. RUST_LOG=relune_introspect=debug relune doc (with DATABASE_URL set).
When RUST_LOG is unset or empty, -v/-q select the level.
Every command requires at least one input. Typical inputs:
| Input | Flag | Notes |
|---|---|---|
| SQL file | --sql <FILE> |
DDL |
| SQL string | --sql-text '<DDL>' |
Not available on lint |
| Normalized schema JSON | --schema-json <FILE> |
From a previous export |
| Live DB | --db-url <URL> |
Read-only introspection; PostgreSQL/MySQL/MariaDB use a 30s statement deadline, and remote TCP connections default to verifying TLS (PostgreSQL verify-full, MySQL/MariaDB verify-identity) — set sslmode=require / ssl-mode=required in the URL to keep encryption without certificate verification |
| SQL dialect | --dialect auto|postgres|mysql|sqlite |
Drives both SQL parsing and relune review rule evaluation. postgres / mysql activate the lock-risk caution rules; sqlite skips them. auto (default) is promoted to the parser-resolved dialect when both inputs agree (so SQL inputs that both look like Postgres run lock-risk under Postgres); when the two sides disagree, auto stays inactive and a REVIEW002 warning is emitted. |
Output path: -o / --out writes a file. render and diff still print to stdout when piped, but for interactive terminals they require --stdout before emitting raw SVG/HTML directly. If the --out parent directory does not exist, Relune reports it as a usage error (exit 2) and names the missing directory.
For SQL files and schema JSON files, Relune currently rejects inputs larger than 8 MiB.
Warning
Avoid passing a live-DB DSN on the command line. A --db-url value is
visible to other users via ps//proc and is recorded in shell history.
For render, inspect, doc, export, and lint, when no input flag
is given Relune falls back to the DATABASE_URL environment variable, so
prefer export DATABASE_URL=... (or a .env loaded by your shell) over
--db-url. An explicit --sql/--schema-json/--db-url flag always takes
precedence over DATABASE_URL.
--db-url introspection runs catalog queries through a small connection pool. Set RELUNE_DB_POOL_MAX_CONNECTIONS to a positive integer to override the default cap (PostgreSQL/MySQL fan out to 6 connections, SQLite uses 1). Non-positive or non-numeric values are ignored and the default applies.
Beyond the 30s per-statement deadline, the whole catalog fetch is bounded by an overall deadline (default 600s) so backends without an enforceable statement timeout (SQLite, or servers that cannot set a session timeout) cannot run unbounded. Set RELUNE_DB_INTROSPECTION_TIMEOUT_SECS to a positive integer to raise or lower it; invalid values are ignored.
The DSN is fully trusted — Relune connects to exactly the host it names with no destination allow/deny-listing — so do not pass an untrusted URL. Introspection is read-only and needs catalog read access: PostgreSQL reads pg_catalog / information_schema; MySQL/MariaDB needs SELECT on information_schema plus SHOW VIEW to read view definitions (missing it yields empty definitions with a logged warning); SQLite reads the database file.
| Code | Meaning |
|---|---|
0 |
Success. For diff --exit-code / review --exit-code, no changes/findings. |
1 |
General/internal failure (I/O, rasterization, unexpected errors). |
2 |
Usage error: bad flags, no input selected, unknown rule id, a missing --out directory, etc. |
3 |
A diagnostic reached the warning threshold under --fail-on-warning (or --deny warning/--deny info on a parser diagnostic). |
10 |
A configured threshold was reached: diff --exit-code/review --exit-code detected changes, review --deny / lint --deny found a finding/issue at or above the threshold. |
lint --deny, review --deny, and diff/review --exit-code all use exit code 10 for "a threshold was reached", so CI can distinguish a policy gate from a general failure (1) or a usage mistake (2).
Generate SVG, HTML, or JSON representations of the ERD. SVG/HTML outputs include tables, views, and PostgreSQL enum types. For SQL-defined views, Relune preserves the full view definition and extracts columns from either an explicit CREATE VIEW ... (cols...) list or simple top-level SELECT items; more complex queries may render the view without inferred columns.
Formats (-f / --format): svg (default), html, graph-json, schema-json.
When rendering svg or html without -o, interactive terminals require --stdout; otherwise Relune asks you to choose a file output path or explicitly opt in to raw stdout.
View options:
| Option | Description |
|---|---|
--viewpoint <NAME> |
Apply a named viewpoint from the active config |
--focus <TABLE> |
Center on a table |
--depth <N> |
Neighbor depth for focus (default 1) |
--group-by none|schema|prefix |
Group tables |
--include <TABLE> |
Repeatable allowlist |
--exclude <TABLE> |
Repeatable denylist |
--theme light|dark |
Visual theme |
--layout hierarchical|force-directed |
Layout algorithm |
--direction top-to-bottom|left-to-right|right-to-left|bottom-to-top |
Primary flow direction |
--edge-style straight|orthogonal|curved |
Edge rendering style |
Other: --stats (stderr statistics), --fail-on-warning (non-zero on warnings).
render validates focus/filter combinations before running:
--depthrequires--focus- the focused table cannot also be excluded
- if
--includeis set, it must contain the focused table - the same table cannot appear in both
--includeand--exclude
relune render --sql schema.sql -o erd.svg
relune render --sql schema.sql --format html -o erd.html
relune render --sql schema.sql --format html --stdout > erd.html
relune render --sql schema.sql --focus orders --depth 2 -o orders.svg
relune render --config relune.toml --sql schema.sql --viewpoint billing -o billing.svg
relune render --sql schema.sql --group-by schema -o grouped.svg
relune render --sql schema.sql --layout force-directed --edge-style orthogonal -o force.svg
relune render --sql schema.sql --include users --include orders -o subset.svg
relune render --schema-json schema.json -o from-json.svgShow a schema summary or details for one table.
| Option | Description |
|---|---|
--table <NAME> |
Table to inspect; omit for summary |
--summary |
Force summary mode |
--format text|json |
Output encoding |
-o, --out <FILE> |
Optional file (else stdout) |
--fail-on-warning |
Return exit code 3 when diagnostics include warnings |
relune inspect --sql schema.sql
relune inspect --sql schema.sql --table orders
relune inspect --sql schema.sql --table orders --format json
relune inspect --sql schema.sql --table orders --format json -o inspect.jsonGenerate Markdown documentation for a schema. Outputs a single Markdown file covering tables, columns, types, constraints, foreign keys, indexes, views, and enums.
| Option | Description |
|---|---|
-o, --out <FILE> |
Optional file (else stdout) |
--fail-on-warning |
Return exit code 3 when diagnostics include warnings |
relune doc --sql schema.sql -o schema.md
relune doc --sql schema.sql
relune doc --db-url 'postgres://user:pass@localhost:5432/mydb' -o schema.mdEmit normalized JSON or diagram text. --format is required.
Formats:
| Format | Description |
|---|---|
schema-json |
Normalized schema as JSON |
graph-json |
Graph representation (nodes/edges) as JSON |
layout-json |
Positioned graph with coordinates plus routing_debug metadata |
mermaid |
Mermaid erDiagram — renders in GitHub/GitLab Markdown |
d2 |
D2 diagram source |
dot |
Graphviz DOT source |
Supports --viewpoint, --focus, --depth, --group-by, --include, --exclude, --layout, --direction, and --edge-style like render for graph-backed exports. export applies the same focus/filter validation rules as render, so --depth requires --focus, the same table cannot appear in both --include and --exclude, and the focused table must stay inside the effective include set.
--fail-on-warning is also available for CI flows that treat parser diagnostics as failures.
layout-json includes graph-level routing_debug.non_self_loop_detour_activations and per-edge routing_debug fields for source/target side policy, slot indices, slot counts, row offsets, and selected channel coordinates.
relune export --sql schema.sql --format schema-json -o schema.json
relune export --sql schema.sql --format graph-json -o graph.json
relune export --sql schema.sql --format layout-json -o layout.json
relune export --sql schema.sql --format layout-json --layout force-directed --edge-style orthogonal -o layout-force.json
relune export --config relune.toml --sql schema.sql --format schema-json --viewpoint billing -o billing.json
relune export --sql schema.sql --format mermaid -o erd.mmd
relune export --sql schema.sql --format d2 -o erd.d2
relune export --sql schema.sql --format dot -o erd.dotRouting debug comparison workflow:
relune export --sql schema.sql --format layout-json > layout.json
relune render --sql schema.sql --format svg -o erd.svg
relune render --sql schema.sql --format html -o erd.htmlRun built-in rules on the schema. Inputs: --sql, --schema-json, or --db-url (no --sql-text on this command).
| Option | Description |
|---|---|
--format text|json |
Report format |
-o, --out <FILE> |
Optional file (else stdout) |
--profile default|strict |
Seed rule set for schema review |
--rules <RULE> |
Repeatable; run only these rules |
--exclude-rules <RULE> |
Repeatable; remove rules from the active set |
--rule-category <CATEGORY> |
Repeatable; keep only structure, relationships, naming, documentation |
--except-table <PATTERN> |
Repeatable; suppress issues for matching tables |
--deny error|warning|info|hint |
Minimum severity for non-zero exit |
--fail-on-warning |
Shortcut for treating warning diagnostics as failures |
relune lint --sql schema.sql
relune lint --sql schema.sql --format json
relune lint --sql schema.sql --format json -o lint.json
relune lint --sql schema.sql --profile strict --rule-category documentation
relune lint --sql schema.sql --deny warning
relune lint --sql schema.sql --rules no-primary-key --rules missing-foreign-key-index
relune lint --sql schema.sql --exclude-rules missing-table-comment --except-table audit_*Rule IDs are kebab-case (for example missing-foreign-key-index, missing-table-comment, circular-foreign-key). default is the everyday schema review profile; strict additionally enforces column comment coverage. Categories are structure, relationships, naming, and documentation.
Compare two schemas across tables, views, and enum types. Provide before and after inputs independently (each side uses one of the following).
Before: --before <FILE>, --before-sql-text '<DDL>', or --before-schema-json <FILE>.
After: --after <FILE>, --after-sql-text '<DDL>', or --after-schema-json <FILE>.
When --before <FILE> or --after <FILE> is used, Relune inspects the file contents and treats schema JSON as schema JSON even if the extension is not .json.
When rendering the diff as svg or html without -o, interactive terminals require --stdout; text and JSON remain safe on stdout by default.
| Option | Description |
|---|---|
-f, --format text|json|markdown|svg|html |
Output format |
-o, --out <FILE> |
Optional file (else stdout) |
--stdout |
Explicitly allow raw SVG/HTML on interactive stdout |
--dialect |
For SQL parsing on both sides |
--fail-on-warning |
Return exit code 3 when diagnostics include warnings |
--exit-code |
Return exit code 10 when schema changes are detected (like git diff --exit-code) |
relune diff --before old_schema.sql --after new_schema.sql
relune diff --before old.sql --after new.sql --format json -o diff.json
relune diff --before old.sql --after new.sql --format markdown
relune diff --before old.sql --after new.sql --format html -o diff.html
relune diff --before old.sql --after new.sql --format html --stdout > diff.html
relune diff --before old.sql --after new.sql --exit-code # exits 10 if changes found
relune --config relune.toml diff --before old.sql --after new.sqlCompare a before schema with an after schema and emit migration risk findings: dropped references, narrowing type changes, NOT NULL on existing data, missing FK indexes, etc. Findings are grouped into four severity buckets — info < warning < caution < breaking — so --deny can gate CI on the level of risk you are willing to ship.
Before: --before <FILE>, --before-sql-text '<DDL>', or --before-schema-json <FILE>.
After: --after <FILE>, --after-sql-text '<DDL>', or --after-schema-json <FILE>.
| Option | Description |
|---|---|
-f, --format text|markdown|json |
Output format (default text) |
-o, --out <FILE> |
Optional file (else stdout) |
--dialect |
Drives both SQL parsing and review rule evaluation. postgres / mysql activate the lock-risk caution rules; sqlite skips them. auto (default) is promoted to the parser-resolved dialect when both inputs agree, and stays inactive (with a REVIEW002 warning) when they disagree. |
--rules <RULE> |
Repeatable; run only these rules (accepts risk/<id> or bare <id>) |
--except-rule <RULE> |
Repeatable; remove rules from the active set |
--except-table <PATTERN> |
Repeatable; suppress findings for matching tables (supports * glob) |
--deny info|warning|caution|breaking |
Exit non-zero when findings reach this severity |
--exit-code |
Exit 10 when any findings are emitted (regardless of severity) |
--list-rules |
List every review rule (with default severity and description) and exit; honors --format text|json only |
--emit-summary <PATH> |
Always write the full review JSON (same shape as --format json) to PATH, even when --deny short-circuits with rc=10 |
Rule IDs are kebab-case under the risk/ namespace. The catalog covers twelve rules:
| Rule ID | Default severity | Dialect |
|---|---|---|
risk/drop-column-referenced |
breaking | any |
risk/drop-table-referenced |
breaking | any |
risk/add-not-null-on-existing |
warning | any |
risk/type-narrow |
breaking | any |
risk/drop-pk-or-unique |
warning (breaking with referencing FK) | any |
risk/add-unique-on-existing |
warning | any |
risk/add-cascade-delete |
warning | any |
risk/fk-without-index |
info | any |
risk/add-index-on-large-table |
caution | postgres / mysql |
risk/add-fk-on-existing |
caution | postgres / mysql |
risk/alter-column-type |
caution | postgres / mysql |
risk/rewrite-table |
caution | mysql |
--rules and --except-rule accept either the fully-qualified form (risk/fk-without-index) or the short form (fk-without-index).
--list-rules is the single source of truth for the rule catalog (CI / docs automation can pipe --format json into jq to enumerate all twelve rules). --emit-summary is intended for CI pipelines that need to read the structured report even when the user-visible run exits with rc=10 (e.g. PR comment generation in a single pass); reusing the same path as --out is rejected as a usage error.
Note
Lock-risk caution rules read schema state, not migration SQL.
Lock-risk caution rules are based on schema state-change diff, not on the migration SQL itself. They flag a state change that — if executed naively — would acquire a problematic lock; they do not read your migration script and cannot detect that you wrote CREATE INDEX CONCURRENTLY or ALGORITHM=INPLACE. Treat the caution as a "make sure you used the safe variant" reminder.
relune review --before old.sql --after new.sql
relune review --before old.sql --after new.sql --format markdown -o review.md
relune review --before old.sql --after new.sql --format json -o review.json
relune review --before old.sql --after new.sql --deny breaking
relune review --before old.sql --after new.sql --except-rule fk-without-index
relune review --before old.sql --after new.sql --except-table audit_*
relune review --before old.sql --after new.sql --exit-code # exits 10 if findings exist
relune review --before old.sql --after new.sql --deny breaking --emit-summary review.json
relune review --before old.sql --after new.sql --dialect postgres --deny caution
relune review --list-rules # text listing of all 12 rules
relune review --list-rules --format json | jq '.[0]'
relune --config relune.toml review --before old.sql --after new.sql