ER Diagram from SQL

Paste your SQL DDL and get Mermaid erDiagram source: one entity per table, columns with their types and PK/FK/UK markers, and crow's-foot relationships inferred from your foreign keys, NOT NULL flags and unique constraints. Nothing is executed and no database is contacted.

Try:
Mermaid erDiagram

About this tool

ER Diagram from SQL reads the DDL you paste — CREATE TABLE, plus ALTER TABLE ... ADD FOREIGN KEY and CREATE UNIQUE INDEX — and writes the matching Mermaid erDiagram source. Each table becomes an entity, each column becomes a TYPE name attribute with optional PK / FK / UK markers, and each foreign key becomes one crow's-foot relationship line. No database is contacted and no statement is executed; it is a lenient text parser, so comments and INSERT / SELECT statements in a dump are simply skipped.

Cardinality is derived from the schema rather than guessed. The parent side is || (exactly one) when every foreign-key column is NOT NULL and |o (zero or one) when any of them is nullable. The child side is o{ (zero or more), or o| when the foreign-key columns are themselves unique in the child table — a primary key, a UNIQUE constraint or a unique index — which makes it a one-to-one. The line is solid -- for a NOT NULL foreign key and dashed .. for a nullable one, because a nullable foreign key means the child can exist without a parent.

Worked example

This DDL:

CREATE TABLE users (
  id INT PRIMARY KEY,
  email VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_id INT NOT NULL REFERENCES users(id),
  total DECIMAL(10,2)
);

produces this diagram source:

erDiagram
    users {
        INT id PK
        VARCHAR(255) email UK
    }
    orders {
        INT id PK
        INT user_id FK
        DECIMAL(10_2) total
    }
    users ||--o{ orders : "user_id"

DECIMAL(10,2) is rewritten as DECIMAL(10_2) on purpose: Mermaid's attribute grammar rejects spaces and commas inside a type token, so types and identifiers are sanitized to safe tokens (TIMESTAMP WITH TIME ZONE becomes TIMESTAMP_WITH_TIME_ZONE) instead of being dropped. Table names that need it, such as a schema-qualified public.users, are double-quoted.

For a wide schema, set Columns to show to key columns only or to entities only, drop the relationship labels, and pick an explicit layout direction. Turn on the *_id inference when the schema enforces its references in application code instead of with real FOREIGN KEY constraints, and turn on the code fence when the destination is a Markdown file or a pull-request comment. Input is capped at 500 tables, because a larger diagram is unreadable in any renderer.

FAQ

Does this render a picture, or just the diagram code?

It outputs Mermaid erDiagram source code, not an image. Paste it into anything that renders Mermaid — a GitHub or GitLab Markdown file, issue or comment, Notion, Obsidian, or the Mermaid live editor — and the picture is drawn there. Turn on the code-fence option to get the output already wrapped in a ```mermaid block, ready to paste into Markdown.

What does `users ||--o{ orders` actually mean?

It is Mermaid's crow's-foot notation: one users row relates to zero or more orders rows. The marker nearest each entity describes that side — || exactly one, |o zero or one, o{ zero or more, |{ one or more. Here the orders.user_id foreign key is NOT NULL, so every order has exactly one user, and nothing makes user_id unique, so a user can have many orders. Make user_id nullable and the line becomes users |o..o{ orders; add a UNIQUE constraint on it and it becomes users ||--o| orders, a one-to-one.

My schema has no FOREIGN KEY constraints — can it still find relationships?

Yes, with the *_id inference turned on. A column such as company_id is linked to a table named company, companys, companyes or companies when one exists in the same DDL, and the column is then marked FK in the diagram. It is a naming heuristic, so it can miss a relationship that does not follow the convention and can occasionally link one you did not mean; explicit FOREIGN KEY constraints are always used and are never duplicated by inference. Self-references are skipped.

Why is my many-to-many join table drawn as its own entity?

Because that is what the schema says, and it is the Mermaid convention. A join table such as post_tags(post_id, tag_id) has two foreign keys, so it renders as two one-to-many relationships into a post_tags entity rather than as a single many-to-many line between posts and tags. Collapsing it would hide any payload columns the join table carries, such as added_at or a position. If you want the collapsed view, edit the two generated lines into one posts }o--o{ tags relationship by hand.

Which SQL is understood, and what is ignored?

Schema-defining statements: CREATE TABLE (inline and table-level PRIMARY KEY, UNIQUE, REFERENCES and FOREIGN KEY clauses), ALTER TABLE ... ADD forms that add columns or constraints, and CREATE INDEX / CREATE UNIQUE INDEX — the unique ones matter, because they can turn a one-to-many into a one-to-one. Everything else in a dump — comments, INSERT, SELECT, DROP, stored procedures, triggers, views — is skipped. MySQL/MariaDB, PostgreSQL, SQLite, SQL Server and generic ANSI quoting styles are normalized. Pasting only INSERT rows or query results returns an error, since there is no schema to draw.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool er-diagram-from-sql "CREATE TABLE users (
  id INT PRIMARY KEY,
  email VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_id INT NOT NULL REFERENCES users(id),
  total DECIMAL(10,2)
);"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/er-diagram-from-sql/?sql=CREATE%20TABLE%20users%20%28%0A%20%20id%20INT%20PRIMARY%20KEY%2C%0A%20%20email%20VARCHAR%28255%29%20NOT%20NULL%20UNIQUE%0A%29%3B%0ACREATE%20TABLE%20orders%20%28%0A%20%20id%20INT%20PRIMARY%20KEY%2C%0A%20%20user_id%20INT%20NOT%20NULL%20REFERENCES%20users%28id%29%2C%0A%20%20total%20DECIMAL%2810%2C2%29%0A%29%3B&dialect=auto&attributes=all&key_markers=true&mark_nullable=true&infer_relations=true&relationship_label=column&direction=auto&fence=true

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.