How to Write a Table Definition in DBML

Updated

To define a table in DBML, write a Table block with the table name followed by a pair of curly braces, then list one column per line inside the braces as name type [settings]. Mark a primary key with [pk] on the column line, and express relationships either with inline [ref: > other_table.column] on a column or with a separate Ref: statement. This syntax works in the DBML editor at dbml.dbdiagram.io, where the diagram is generated as you type.

The basic table block

A table definition has three parts: the Table keyword, the table name, and a braced body containing columns.

Table users {
  id integer
  username varchar
  created_at timestamp
}

Rules that matter in practice:

  • The table name follows Table directly. Use double quotes if the name contains spaces or reserved words: Table "order items" { ... }.
  • Each column line is column_name column_type. The type is free-form text, so varchar, varchar(255), int, and uuid are all accepted; DBML does not validate types against a specific database.
  • Settings go in square brackets after the type, separated by commas: [pk], [not null], [unique], [default: value], [note: 'text'].
  • Indentation is cosmetic. Braces and line breaks are what delimit the block.

A more complete example:

Table users {
  id integer [pk, increment]
  email varchar(255) [not null, unique]
  display_name varchar [note: 'shown in the UI']
  is_active boolean [default: true]
  created_at timestamp [default: `now()`]
}

Note that increment and `now()` are passed through as written; they are annotations for readers and for export, not something the editor evaluates.

Primary keys, composite keys, and indexes

A single-column primary key is just [pk] on that column. For a composite key, put [pk] on each participating column — DBML treats multiple pk columns in one table as a composite primary key.

Table memberships {
  user_id integer [pk]
  group_id integer [pk]
  role varchar
}

Indexes are declared as table-level settings inside the same brackets, after the column list:

Table posts {
  id integer [pk]
  author_id integer
  slug varchar
  published_at timestamp

  indexes {
    slug [unique]
    (author_id, published_at)
  }
}

The indexes block is optional and sits inside the table braces. A parenthesized list creates a composite index; [unique] or [name: 'idx_name'] can be attached to an entry.

Expressing references

There are two equivalent ways to declare a relationship. Inline is shorter for one-off foreign keys:

Table posts {
  id integer [pk]
  author_id integer [ref: > users.id]
  title varchar
}

The separate form is easier to read when a table has many relationships or when you want to name them:

Table posts {
  id integer [pk]
  author_id integer
  title varchar
}

Ref: posts.author_id > users.id
Ref name: "post_author" {
  posts.author_id > users.id
}

The operator encodes cardinality, read from the left side to the right:

Operator Meaning
> many-to-one
< one-to-many
- one-to-one
<> many-to-many

So posts.author_id > users.id reads as "many posts belong to one user." Getting the direction backwards is the most common mistake — it changes the arrowhead in the generated diagram, not just the text.

Checking your definition and finding the docs

The editor at dbml.dbdiagram.io renders the diagram live, so the fastest verification is to paste the definition and confirm that every table appears with the expected columns and that each relationship draws an arrow between the correct tables. If a table is missing, look for an unbalanced brace or a column line placed outside the braces; if a reference is missing, check that both table and column names match exactly, since references are resolved by name and are case-sensitive in practice.

For syntax beyond what is covered here — enums, table groups, notes, table partials, and database-specific type annotations — the site's own documentation and example files are the authoritative reference, and the editor's sample schema is a working definition you can copy and modify rather than write from scratch.