DSL syntax
.dbschema is a database structure format you can read at a glance: one column per line, relations declared on their own. Paste it into the workspace or open it in VS Code and the diagram appears.
Quick start
Two tables and one foreign key make the smallest possible diagram. Copy this, then paste it into Import in the workspace.
table Users {
PK Id bigint not null
Email nvarchar(255) not null "Login email"
}
table Orders {
PK Id bigint not null
FK UserId bigint not null
}
relation FK_Orders_Users {
Orders.UserId N -> 1 Users.Id
}Only three things to know: table declares a table, each line is a column, and relation declares a relation. Anything after // is a comment.
Tables
table Name "description" { … }. You can prefix the name with a schema (sales.Orders); without one it is dbo. The description is optional and shows next to the card title. Names are case-sensitive; keywords are not.
table Users "System users" {
PK Id bigint not null "User ID"
}
// With a schema; dbo when omitted
table sales.Orders {
PK Id bigint not null
}Columns
The format is [flags] Name Type [null | not null] [default value] ["comment"], one per line. Aligning columns is just for readability; the amount of whitespace does not matter.
table Products {
PK Id bigint not null "Product ID"
UQ Sku nvarchar(64) not null
Name nvarchar(200) not null
Price decimal(18,2) not null default 0
Note nvarchar(4000) null "Notes"
IsActive bit not null default 1
}Flags
| Flag | Meaning |
|---|---|
PK | Primary key; implies not null |
FK | Foreign key marker; visual only, declare the link with relation |
UQ | Unique |
IDX | Indexed marker; real indexes use the index statement |
Rules
| Case | How it is read |
|---|---|
| Several flags at once | PK UQ Id bigint |
| No null / not null | Nullable by default (except PK) |
| One type argument | Length, e.g. nvarchar(255) |
| Two type arguments | Precision and scale, e.g. decimal(18,2) |
| String at the end of the line | Column comment, shown on the card |
| default | A number, string or identifier, e.g. default 0, default "draft" |
Groups
Groups are your own functional categories (say, "Orders" or "Members"). They are not database schemas and can span several. Tables in the same group are laid out together in one color, and the toolbar can show a single group.
// 1. Declare the group and list its members
group Identity "Identity and access" {
Users
Roles
}
// 2. Declare only the description; mark members on each table
group Sales "Orders and payments"
table Orders in Sales {
PK Id bigint not null
}A table belongs to at most one group. If you write table X in G and G is not declared, G becomes a group with no description.
Indexes
Indexes are declared on their own; composite indexes keep the column order you list. When a foreign key column has no index, the workspace shows a hint (the diagram is not affected).
index IX_Posts_Author_CreatedAt on Posts(AuthorId, CreatedAt)
unique index UX_Users_Email on Users(Email)Relations
The left side of the arrow holds the foreign key; the right side is the table it points to. Posts.AuthorId N -> 1 Users.Id reads "many Posts belong to one User". This direction also decides upstream / downstream when you focus a table.
relation FK_Posts_Users {
Posts.AuthorId N -> 1 Users.Id
}
// Composite foreign key
relation FK_OrderLines_Orders {
OrderLines.(OrderId, TenantId) N -> 1 Orders.(Id, TenantId)
}| Syntax | Meaning |
|---|---|
N -> 1 | Many-to-one (most common: the left side holds the foreign key) |
1 -> N | One-to-many |
1 -> 1 | One-to-one |
N -> M | Many-to-many |
The FK flag on a column does not create a relation by itself; every line on the diagram comes from a relation.
Other formats
SQL
In the workspace, Import → SQL takes plain CREATE TABLE for MySQL, SQL Server, PostgreSQL and SQLite. Column-level REFERENCES and table-level FOREIGN KEY both become relations, and the result is saved as DSL. In VS Code, use "DBSchema: Import SQL as .dbschema".
CREATE TABLE users (
id bigint PRIMARY KEY,
email text NOT NULL
);
CREATE TABLE orders (
id bigint PRIMARY KEY,
user_id bigint NOT NULL REFERENCES users(id)
);Markdown
Name the file .schema.md and put the DSL in a fenced code block tagged dbschema, so docs and structure live in one file.
# Orders module
```dbschema
table Orders {
PK Id bigint not null
}
```JSON
Name the file .schema.json. It is the full structure the workspace exports, handy for scripts or backups.
Shortcuts
Shared by the web app and the VS Code extension; rows marked "web" only work on the web.
| Keys | What it does |
|---|---|
Ctrl / Cmd + F | Search tables or columns |
Ctrl / Cmd + wheel | Zoom the canvas |
Drag background | Pan (move mode) / box-select (select mode) |
Click a table name | Focus: related tables light up, the rest dim; click again to clear |
Click a column | Column focus: only that column and its foreign key partners light up |
Double-click a table or column | Jump to its DSL definition |
Tab | Move through tables with the keyboard |
Enter / Space | Focus the current table (press again to clear) |
Shift + Enter | Jump to the table definition |
Esc | Clear focus, close dialogs |
Ctrl / Cmd + click a table | Multi-select (web); Delete removes the selection |
Delete | Delete the clicked or selected tables; undo from the notice (web) |
Ctrl / Cmd + A | Select every table on screen (web) |
Ctrl / Cmd + Z | Undo the last edit (web) |
Ctrl / Cmd + Shift + Z, Ctrl + Y | Redo (web) |
Ctrl / Cmd + D | Duplicate the selected or focused tables (web) |
Ctrl / Cmd + C | Copy the DSL of the selected or focused tables (web) |
+ / - | Zoom in / out |
Shift + 1 | Zoom to fit the whole diagram |
Errors and hints
SCHEMA_* codes are errors that make the diagram wrong; LINT_* codes are only design hints. A parse error never sinks the whole file: everything that can be read is still drawn, and the line that could not be read is listed with its line and column.
| Code | Meaning and fix |
|---|---|
SCHEMA_PARSE_ERROR | This line cannot be read. The message gives line:column; usually a missing bracket, a stray symbol or a misspelled keyword. |
SCHEMA_DUPLICATE_TABLE / COLUMN / INDEX | A table, column or index with the same name is declared twice. |
SCHEMA_UNKNOWN_TABLE / COLUMN | A relation, index or group points to a table or column that does not exist. Check the case (Users ≠ users). |
SCHEMA_RELATION_SOURCE_NOT_FOUND / TARGET_NOT_FOUND | One side of the relation arrow cannot be found. |
SCHEMA_INVALID_CARDINALITY | Cardinality can only be 1, N or M. |
SCHEMA_INVALID_COMPOSITE_RELATION | Every line in one relation block must point to the same source / target tables. |
SCHEMA_DUPLICATE_GROUP / CONFLICTING_GROUP | A group is declared twice, or a table is put in two groups. |
LINT_FK_NO_INDEX | Hint: the foreign key column has no index, so JOINs may be slow. The diagram is not affected. |
LINT_NO_PK | Hint: this table has no primary key. |
LINT_EMPTY_TABLE | Hint: this table has no columns. |
LINT_NAMING / LINT_TYPE_SUFFIX | Hint: naming style is inconsistent. |