Tutorials

Turn a DBML schema into an ER diagram

Paste a DBML schema, get an editable ER diagram, edit it, and get DBML back out — with the parser's limits named up front.


If you already have a schema in DBML — the text format dbdiagram.io uses — you can paste it into diagrams.info and get an editable ER diagram out of it. No account, no install, and the schema stays in your browser.

Before the steps, the limits, because a tool that silently drops half your file is worse than one that refuses it.

What comes across, and what doesn’t

DBMLWhat happens
Table … { } and its columnsA table, one row per column, each column’s type text kept as written
[pk]Marked PK on that row
Inline [ref: > Other.id]A connector from this row to the referenced row; this row is marked FK
Ref: A.a > B.b, and the Ref { … } block formSame — a row-to-row connector
<, > and - in a refRead for direction. The foreign-key side is normalised to be the connector’s source
[unique]Parsed, but the diagram has nowhere to show it, and it does not survive an export
Enum … { }Read past. No enum shape is drawn. A column typed with an enum keeps the enum’s name as its type text, and that is all
Indexes { … }Skipped, deliberately, so index expressions don’t become phantom columns
Note, TableGroup, ProjectParsed past and ignored. Nothing is drawn
Other column settings — increment, not null, defaultIgnored

That list is the whole of it. The parser is not a full DBML implementation; it covers the subset that has a picture to draw.

1. Open the editor

Go to diagrams.info. It opens straight onto a canvas; dismiss the welcome panel. One thing to know first: the editor is mouse-only. There are no touch handlers in it yet, so this is a desktop workflow.

2. Paste the schema

Click Import in the top bar. In the dialog, choose Database — tables as DBML (the other tab, Diagram, is for whole-board JSON), stay on Import, and paste:

Table users {
  id int [pk]
  email varchar [unique]
  created_at timestamp
}

Table posts {
  id int [pk]
  user_id int [ref: > users.id]
  title varchar
  body text
}

Table comments {
  id int [pk]
  post_id int [ref: > posts.id]
  author_id int [ref: > users.id]
  body text
}

Load file… accepts .dbml, .txt and .sql, but only reads the file as text — the parser is still DBML, so a raw CREATE TABLE dump imports nothing and you get “No tables found.”

Click Generate diagram. You should see “Imported 3 tables and 3 relationships.”

3. What you got

Three table boxes, laid out in a rough square near the top-left of the area you are looking at, packed so taller tables don’t leave gaps. Each row shows the column name, its type, and a key badge: PK for a [pk] column, FK for any column on the referencing side of a ref.

The relationships are row-to-row connectors: the line starts at posts.user_id and ends at users.id, not at the edge of the box. Move a table and the line stays attached to the right rows.

The import merges into whatever is already on the canvas rather than replacing it, and the whole thing goes in as a single undo step. One Ctrl+Z (or Cmd+Z) removes every table and every connector it just created.

4. Add cardinality

Imported connectors are plain lines: crow’s-foot markers are a styling choice, and the import does not guess them for you. Click a connector to select it. Its toolbar has a Relationship dropdown with a marker per end — , 1, N, 0..1, 0..N — plus presets that set both ends at once: 1 — 1, 1 — N, N — N. For posts.user_id → users.id you want 1 — N, with the 1 at the users end.

5. Edit the tables

Imported tables are ordinary diagram elements, so they behave like one you drew by hand:

  • Rename by double-clicking the title bar; drag that same bar to move the table.
  • Edit a cell by clicking it and typing — column and type are plain text inputs.
  • Toggle a key by clicking the badge at the end of the row. It cycles PKFK.
  • Add a row with + Add row, or by pressing Tab out of the last row’s type field.
  • Remove a row with the ×. Any connector attached to it goes too.
  • Link two rows by dragging one table’s row onto a row in another table.

6. Get DBML back out

Click Export in the top bar, pick Database — tables as DBML, and the current board comes back as DBML — Copy, or Download .dbml. Two things before you rely on the round trip:

  • Only table elements and row-to-row connectors are exported. A plain box-to-box line between two tables is not a relationship to the exporter, and produces no Ref.
  • What does not survive: unique, enums, indexes, notes, and everything else from the table above. A column with no type is written as varchar; names that aren’t plain identifiers get double-quoted, and duplicate table or column names are suffixed _2, _3 so the output stays valid.

Edge cases in the parser

Worth knowing if a ref quietly fails to appear:

  • A composite refRef: a.(x, y) > b.(p, q) — uses the first column on each side only.
  • A schema qualifier is dropped: public.users.id is read as users.id.
  • A table alias (Table users as U) is not tracked, so a ref written against U will not resolve.
  • Two tables with the same name: the first definition wins, the second is ignored.

The first two are usually harmless: a composite ref still draws, on its first column, and a qualified name still resolves. The last two lose something silently — a ref against an alias never draws, and a duplicated table name means the second block simply isn’t there.

Where the diagram lives

In your browser. The board is saved to localStorage about a second after you stop editing, there is no account, and the schema you pasted is never sent anywhere — useful if it is one you are not allowed to paste into a hosted tool. The obvious cost: clear your site data and it is gone. Use Export → Diagram for a JSON file you can re-import, and keep the .dbml.