ErdDocs

Formats

ErdDocs reads ten formats and writes eight. Each entry below says what we make of the format and, where there is one, the limit — a list of logos would be marketing, and the limits are the part that saves you an afternoon.

What you can paste

The format is detected from the text; in the tool, the selector above the schema panel shows what was decided and lets you disagree.

  • A dump from pg_dump --schema-only or mysqldump --no-data, a migration file, or any script of CREATE TABLE statements.

    PostgreSQL, MySQL, SQLite and T-SQL are read, PostgreSQL and MySQL in full, including comments, which become the description column of the data dictionary. Partitions are folded back into the parent table — a real dump can carry fifty-five of them for one table. Relations the dump never declared are recovered from column names (user_id → users) and drawn dashed, because Rails, Django and WordPress schemas often declare almost no foreign keys at all.

  • schema.prisma, exactly as it sits in your repository.

    We draw the database Prisma would create, not the models: @@map and @map names win, a relation shows on the side that holds the scalar foreign key, and an implicit many-to-many becomes the join table Prisma generates for it. cal.com — 105 models — reads with no errors.

  • The dbdiagram.io language: Table blocks and Ref lines.

    Tables, columns, settings, enums and every form of Ref, including the inline one. Written by hand or exported from another tool, it makes no difference.

  • An erDiagram block — the kind that lives in a README.

    Both ends of a Mermaid relation carry their own glyphs, and they are different sets on the left and the right; we read the pair rather than guessing from one side. Attribute blocks with PK and FK markers come through as keys.

  • PlantUML

    An @startuml file with entity blocks.

    Entities, their attributes, primary and foreign key stereotypes, and the relation glyphs between them. PlantUML is also an export, so a diagram can go out the way it came in.

  • The models.py of an app, pasted as it is — no manage.py, no settings, no installation.

    We draw the tables Django creates: a ForeignKey named author becomes the column author_id, a model without an explicit key gets id, and a ManyToManyField becomes a table of its own. on_delete and default are executed by Django in Python and never reach the database, so they are not drawn — only db_default is. One honest gap, stated once per file: Django prefixes table names with the app label, and a pasted file cannot say which app it came from; Meta.db_table is used wherever it appears.

  • Declarative models — Column, ForeignKey, __tablename__.

    Column types map to their SQL equivalents, ForeignKey becomes a relation, and a composite primary key stays composite. relationship() adds nothing that the columns do not already say, so it is read but never invents an edge.

  • sequelize.define or Model.init, together with the associations below them.

    field: overrides win over the attribute name, and tableName over the model name. A column that only an association declares — Order.belongsTo(Customer, { foreignKey: "customer_id" }) — is synthesized from the target key’s type, so the relation does not point at a column missing from the card. A name that cannot be confirmed is never invented.

  • @Entity classes with their decorators.

    The naming rules come from TypeORM’s own DefaultNamingStrategy rather than from memory: the table is snake_case of the class, the join table is snake_case(first_prop_second) — but columns stay camelCase (authorId). That asymmetry is why half the SnakeNamingStrategy packages on npm exist. Ownership decides existence, as in TypeORM itself: @OneToMany alone produces nothing, @OneToOne gives a column only where @JoinColumn sits, @ManyToMany a table only where @JoinTable sits.

  • Laravel

    The contents of database/migrations, pasted one after another.

    Migrations are history rather than a declaration, so they are replayed in order: create makes a table, a later table() adds a column, drops another, renames a third, and the result is the sum. down() is deliberately ignored — every file contains the instructions to undo itself, and a folder read literally would parse into almost nothing. foreignId()->constrained() is resolved by Laravel’s own guess (user_id → users), but the relation is only drawn when that table is in the text you pasted.

What you can take away

Every export is free and carries a small ErdDocs mark on the images; the $9 license removes it. The free limit applies to how many tables get drawn, not to what gets converted — a text export always carries the whole schema.

  • PNG image

    The canvas as you arranged it, at the resolution a document needs.

  • SVG image

    Vector, so it survives zooming in a wiki or a PDF. This is also what the README embed points at.

  • An erDiagram block to commit next to the code; GitHub renders it natively.

  • Opens in dbdiagram.io, and is the most readable way to keep a schema under review.

  • PlantUML

    example →

    For teams whose documentation pipeline already speaks it.

  • SQL (PostgreSQL or MySQL)

    example →

    The point is not SQL to SQL, which is a no-op, but the inputs that are not SQL: Prisma, DBML or ORM models become working DDL. Relations we recovered from column names are printed commented out — otherwise the script would pass on an empty database and fail on a full one.

  • Data dictionary

    example →

    The document, not the picture: every table, column, type, nullability, default, index and relation, printable to PDF from the browser. This is the part the license is for.

  • README embed, iframe embed, project file

    example →

    A markdown snippet plus the SVG it points at; an iframe for a page you own; and an .erddocs.json that is a share link written to disk, for schemas too big for a URL.

Questions before you paste

How does it know which format I pasted?

ErdDocs looks at the text. A schema.prisma has model blocks, a Mermaid file opens with erDiagram, Laravel migrations are PHP with Schema::create in them — the sniffs are specific enough that the diagram languages are checked before SQL, which is the fallback rather than a positive match. In the tool, the selector above the schema panel shows what was decided, and you can overrule it: an ambiguous file, such as a Prisma schema quoted inside a JavaScript file, is exactly when that matters.

Does the format change what the data dictionary contains?

Only in as much as the source carries the facts. A SQL dump knows about indexes and comments, so those columns fill in; a Mermaid diagram knows neither, so they stay empty rather than being invented. Everything a format does state — tables, columns, types, nullability, defaults, keys, relations — reaches the document the same way whichever format it came from.

My schema has no foreign keys at all. Is it worth pasting?

Yes, and this is common: Rails, Django and Laravel projects often declare relations in the application rather than in the database, and a WordPress dump has none whatsoever. Relations are recovered from column names — user_id points at users — and drawn as dashed lines so the guess is never mistaken for something your schema actually declares. One switch hides them everywhere, including the dictionary and every export.

Is anything uploaded when I paste?

No. Every parser on this page runs in your browser, and the schema never leaves the tab: there is no request that carries it, which is checkable in your own network panel. That is also why there is no account — there is nothing on our side to attach one to.

Nothing to paste yet? The example schemas are eleven real domains with the SQL to copy. Or start from your own dump on the home page — whatever the format, it is read in the browser and never uploaded.

Not sure what the picture is called? ER diagram explains the notation from entities up, and schema diagram covers the narrower term for the tables a database actually holds — including the difference between the two.