DBML Schema
Author DBML that is readable first and SQL-faithful second. Prefer clear table names, explicit keys, and consistent relationship direction over clever compression.
Workflow
- Determine the job shape:
- Create a new schema from requirements.
- Refine an existing
.dbml file.
- Translate SQL or a live database into DBML, then normalize the result.
- Model the core domain first:
- Add
Project metadata if it improves context.
- Define
Enum values before tables that use them.
- Create tables with primary keys, nullability, unique constraints, defaults, checks, and indexes.
- Add relationships deliberately:
- Use inline
ref only when the foreign key column is already obvious in that table.
- Use short or long
Ref form when relationships are cross-schema, composite, or easier to scan separately.
- Be careful with one-to-one ordering because the foreign key side matters.
- Reduce repetition only after the base schema is clear:
- Use
TablePartial for shared audit fields, soft-delete fields, or repeated indexes.
- Use
TableGroup and notes for documentation and visualization, not as a substitute for schema design.
- Validate and round-trip:
- If CLI or JS tooling is available, parse DBML and export SQL to catch structural mistakes early.
- If the schema came from SQL, compare the normalized DBML back against the source intent.
Authoring Rules
- Keep one concern per line: one column, one relationship, one enum value, one record row.
- Prefer explicit column settings like
[pk, not null] over relying on assumptions.
- Quote identifiers with double quotes only when they contain spaces or special characters.
- Use single quotes for string literals and backticks for SQL expressions such as defaults or checks.
- Prefer true junction tables over
<> when the many-to-many relationship needs attributes, audit fields, or direct SQL fidelity.
- Use
<> only when the relationship is conceptual and no join-table payload is required.
- Inject
TablePartial only after checking for field/index conflicts. Local table definitions win; otherwise the last injected partial wins.
- Use
records only when sample data helps documentation, testing, or examples. Do not invent fake production-like data unless the user asked for samples.
Default Shape
Start from this structure and remove sections you do not need:
Project app {
database_type: 'PostgreSQL'
Note: 'Short description of the schema'
}
Enum user_role {
admin
member
}
TablePartial audit_fields {
id uuid [pk, not null, default: `gen_random_uuid()`]
created_at timestamp [not null, default: `now()`]
updated_at timestamp [not null, default: `now()`]
}
Table users {
~audit_fields
email varchar(255) [not null, unique]
role user_role [not null, default: 'member']
indexes {
email [unique]
}
}
Table posts {
~audit_fields
user_id uuid [not null, ref: > users.id]
title varchar(255) [not null]
body text
checks {
`length(title) > 0` [name: 'chk_posts_title_not_empty']
}
}
Conversion And Validation
- Use the DBML CLI when you need fast round-trips:
dbml2sql schema.dbml --postgres
sql2dbml schema.sql --postgres
db2dbml postgres '<connection-string>' -o schema.dbml
- Use
@dbml/core when the task needs parsing, transformation, or programmatic validation inside Node.js.
- After import from SQL or a live database, clean up naming, factor repeated columns into partials only if it improves clarity, and verify relationships/indexes were preserved.
Resources
- Read references/dbml-reference.md when you need exact syntax, feature coverage, or reminders about edge cases such as composite foreign keys, records, or partial precedence.
1---2name: dbml3description: Create, extend, review, and normalize database schemas written in DBML (Database Markup Language). Use when authoring or editing `.dbml` files, translating SQL schemas into DBML, documenting tables and relationships, or validating DBML constructs such as `Table`, `Ref`, `Enum`, `TablePartial`, `TableGroup`, `checks`, `indexes`, and `records`.4---56# DBML Schema78Author DBML that is readable first and SQL-faithful second. Prefer clear table names, explicit keys, and consistent relationship direction over clever compression.910## Workflow11121. Determine the job shape:13 - Create a new schema from requirements.14 - Refine an existing `.dbml` file.15 - Translate SQL or a live database into DBML, then normalize the result.162. Model the core domain first:17 - Add `Project` metadata if it improves context.18 - Define `Enum` values before tables that use them.19 - Create tables with primary keys, nullability, unique constraints, defaults, checks, and indexes.203. Add relationships deliberately:21 - Use inline `ref` only when the foreign key column is already obvious in that table.22 - Use short or long `Ref` form when relationships are cross-schema, composite, or easier to scan separately.23 - Be careful with one-to-one ordering because the foreign key side matters.244. Reduce repetition only after the base schema is clear:25 - Use `TablePartial` for shared audit fields, soft-delete fields, or repeated indexes.26 - Use `TableGroup` and notes for documentation and visualization, not as a substitute for schema design.275. Validate and round-trip:28 - If CLI or JS tooling is available, parse DBML and export SQL to catch structural mistakes early.29 - If the schema came from SQL, compare the normalized DBML back against the source intent.3031## Authoring Rules3233- Keep one concern per line: one column, one relationship, one enum value, one record row.34- Prefer explicit column settings like `[pk, not null]` over relying on assumptions.35- Quote identifiers with double quotes only when they contain spaces or special characters.36- Use single quotes for string literals and backticks for SQL expressions such as defaults or checks.37- Prefer true junction tables over `<>` when the many-to-many relationship needs attributes, audit fields, or direct SQL fidelity.38- Use `<>` only when the relationship is conceptual and no join-table payload is required.39- Inject `TablePartial` only after checking for field/index conflicts. Local table definitions win; otherwise the last injected partial wins.40- Use `records` only when sample data helps documentation, testing, or examples. Do not invent fake production-like data unless the user asked for samples.4142## Default Shape4344Start from this structure and remove sections you do not need:4546```dbml47Project app {48 database_type: 'PostgreSQL'49 Note: 'Short description of the schema'50}5152Enum user_role {53 admin54 member55}5657TablePartial audit_fields {58 id uuid [pk, not null, default: `gen_random_uuid()`]59 created_at timestamp [not null, default: `now()`]60 updated_at timestamp [not null, default: `now()`]61}6263Table users {64 ~audit_fields65 email varchar(255) [not null, unique]66 role user_role [not null, default: 'member']6768 indexes {69 email [unique]70 }71}7273Table posts {74 ~audit_fields75 user_id uuid [not null, ref: > users.id]76 title varchar(255) [not null]77 body text7879 checks {80 `length(title) > 0` [name: 'chk_posts_title_not_empty']81 }82}83```8485## Conversion And Validation8687- Use the DBML CLI when you need fast round-trips:88 - `dbml2sql schema.dbml --postgres`89 - `sql2dbml schema.sql --postgres`90 - `db2dbml postgres '<connection-string>' -o schema.dbml`91- Use `@dbml/core` when the task needs parsing, transformation, or programmatic validation inside Node.js.92- After import from SQL or a live database, clean up naming, factor repeated columns into partials only if it improves clarity, and verify relationships/indexes were preserved.9394## Resources9596- Read [references/dbml-reference.md](./references/dbml-reference.md) when you need exact syntax, feature coverage, or reminders about edge cases such as composite foreign keys, records, or partial precedence.