Sequelforge
Language reference

The Sequelforge DSL

A compact, declarative language for describing relational schemas. Inspired by DBML, with a few opinionated extensions. Write tables and references in plain text and get a live, animated ER diagram plus production-ready DDL for PostgreSQL, MySQL 8, SQL Server, Oracle, and SQLite.

Quickstart

Sequelforge schemas are plain text. You declare Tables, optionally connect them with References, and the diagram updates as you type. Here is the smallest useful schema:

schemaforge
Table users {
  id     uuid         [pk]
  email  varchar(255) [unique, not null]
}

Paste that into the editor and you immediately get a table card with a primary key and a unique, non-null column.

Tables

A table has a name and a body of columns. Each column is a name, a type, and an optional list of attributes in square brackets.

schemaforge
Table products {
  id          uuid          [pk]
  sku         varchar(64)   [unique, not null]
  name        varchar(160)  [not null]
  price_cents int           [not null]
  active      boolean       [not null, default: true]
}

Tables can live in a schema and carry an alias for use in references:

schemaforge
Table shop.orders as O {
  id  uuid  [pk]
}

Column types

Any identifier is accepted as a type, so you are never blocked. These map to native PostgreSQL types on export, optionally with length/precision arguments like varchar(255) or numeric(10, 2).

uuidintbigintsmallintserialvarchartextbooleantimestamptztimestampdatetimenumericfloatjsonjsonbbytea

Marking an integer column with increment exports it as SERIAL / BIGSERIAL.

Column attributes

Attributes go inside [ ], separated by commas. They fine-tune constraints and metadata for a column.

pkMarks the column as the primary key.
uniqueAdds a UNIQUE constraint.
not nullAdds a NOT NULL constraint.
incrementAuto-increment — exported as SERIAL / BIGSERIAL.
default: <value>Default literal or function call, e.g. default: now() or default: 'pending'.
note: "<text>"Free-form comment, exported as a SQL COMMENT.
ref: <rel> table.columnInline foreign key. The relationship operator is one of > < - <>.
schemaforge
Table orders {
  id          uuid         [pk]
  user_id     uuid         [ref: > users.id, not null]
  status      order_status [not null, default: 'pending']
  total_cents int          [not null]
  placed_at   timestamptz  [not null, default: now(), note: "UTC"]
}

References & relationships

Relationships can be written inline on a column (ref:)or as a standalone Ref statement. The operator encodes the cardinality:

>Many-to-one — the source points to one target row.
<One-to-many.
-One-to-one.
<>Many-to-many.
schemaforge
// Inline, on the column:
Table posts {
  id      uuid [pk]
  author  uuid [ref: > users.id]
}

// Standalone, optionally named:
Ref fk_posts_author: posts.author > users.id

Cardinality — (min,max), Chen & Crow's Foot

True ER min-max cardinalities, shown in either Chen or Crow's Foot notation — switchable live in the toolbar. Neither DBML nor Mermaid does this.

Annotate a relationship with explicit (min,max) cardinalities per end, plus an optional label (the relationship verb). from is the source end (the table holding the foreign key), to is the target end. max may be a number, N, or * for “many”.

schemaforge
Table projects {
  id    uuid         [pk]
  owner uuid         [ref: > employee.id,
                      from: (1,1), to: (0,*), label: "manages"]
}

// or on a standalone Ref:
Ref: projects.owner > employee.id [from: (1,1), to: (0,*), label: "manages"]

Read it look-here: a project participates in (1,1) “manages” relationships (exactly one employee), while an employee participates in (0,*) (any number of projects). If you omit the cardinalities, Sequelforge derives sensible defaults from the operator and the not-null status of the foreign key.

Use the toolbar switch to flip the whole diagram between the two notations:

Crow's FootDirect edge with crow's-foot markers derived from (min,max): a bar = one, a crow's foot = many; a circle = optional (min 0), a bar = mandatory (min ≥ 1). So (0,*) → ○<, (1,1) → ||.
ChenThe relationship becomes a labelled rhombus (◇) between the tables, with the (min,max) on each connecting edge.

Referential actions

Standalone references accept delete and update actions, exported as ON DELETE / ON UPDATE clauses.

schemaforge
Ref: order_items.order_id > orders.id [delete: cascade]
Ref: orders.user_id > users.id [delete: restrict, update: no action]

Valid actions: cascade, restrict, set null, set default, no action.

Generalization & specialization

This is an ER concept that DBML and Mermaid can't express. Sequelforge draws it as a proper IS-A hub.

A generalization relates a supertype to a set of subtypes (an IS-A hierarchy). Declare the supertype, then list its subtypes. Two constraints describe the set:

disjointAn instance belongs to at most one subtype (default).
overlappingAn instance may belong to several subtypes at once.
totalEvery supertype instance must be in some subtype.
partialA supertype instance need not be in any subtype (default).
schemaforge
Table person {
  id    uuid         [pk]
  email varchar(255) [unique, not null]
}

Table employee { id uuid [pk]  hired_on date }
Table customer { id uuid [pk]  loyalty_points int }

Generalization person [disjoint, total] {
  employee
  customer
}

In the diagram, subtypes connect into a circular hub marked d (disjoint) or o (overlapping); a total generalization doubles the hub's ring, and a hollow triangle points at the supertype. On export, each subtype key becomes a foreign key to the supertype key (table-per-type).

Weak entities

Another ER concept missing from DBML and Mermaid — existence dependence with a partial key.

A weak entity has no identity of its own. It is identified by an owning (identifying) entity plus a partial key (discriminator). Prefix the table with Weak and name the owner with depends on:

schemaforge
Table projects {
  id   uuid         [pk]
  name varchar(160) [not null]
}

Weak Table task depends on projects {
  project_id  uuid         [ref: > projects.id, not null]
  number      int          [partial key]
  title       varchar(160) [not null]
}

Weak entities are drawn with the classic ER double border, the partial key gets a dashed underline, and the identifying relationship to the owner is a double line. On export, the weak entity's primary key becomes the composite of the owner's foreign key and the partial key — here (project_id, number).

Indexes

Add an indexes block inside a table. Single or composite columns are supported, each with optional unique and a custom name.

schemaforge
Table orders {
  id        uuid        [pk]
  user_id   uuid        [not null]
  placed_at timestamptz [not null]

  indexes {
    (user_id, placed_at) [name: 'idx_orders_user_placed']
    user_id [unique]
    placed_at
  }
}

Enums

Declare an enum and use its name as a column type. On export it becomes a PostgreSQL CREATE TYPE ... AS ENUM; the other dialects (MySQL 8, SQL Server, Oracle, SQLite) map it to an inline ENUM or a CHECK constraint.

schemaforge
Enum order_status {
  pending
  paid
  shipped
  cancelled [note: "terminal state"]
}

Table groups

Groups are a visual aid — they bundle related tables together without affecting the generated SQL.

schemaforge
TableGroup commerce {
  orders
  order_items
  products
}

Comments

Three comment styles are supported and ignored by the parser.

schemaforge
// a line comment
# also a line comment
/* a
   block comment */

Full example

Everything together — the same schema that loads by default in the editor.

schemaforge
Enum employment_type {
  full_time
  part_time
  contractor
}

Table person {
  id    uuid         [pk]
  email varchar(255) [unique, not null]
}

Table employee {
  id       uuid            [pk]
  hired_on date            [not null]
  kind     employment_type [not null]
}

Table customer {
  id             uuid [pk]
  loyalty_points int  [not null, default: 0]
}

Generalization person [disjoint, total] {
  employee
  customer
}

Table projects {
  id    uuid         [pk]
  name  varchar(160) [not null]
}

Weak Table task depends on projects {
  project_id uuid         [ref: > projects.id, not null]
  number     int          [partial key]
  title      varchar(160) [not null]
}

Migration timeline

Everything runs client-side — your migration scripts never leave the browser.

Drop a set of Flyway migration scripts on /timeline and watch your schema evolve version by version: each migration is applied in order and the diagram animates from one version to the next, with a diff of what changed between them.

Files follow the standard Flyway naming convention V<version>__<name>.sql and are replayed in version order (so V2 runs before V10). All five SQL dialects — PostgreSQL, MySQL 8, SQL Server, Oracle, and SQLite — are supported, and the dialect is auto-detected, just like SQL import.

schemaforge
V1__init.sql
V2__add_orders.sql
V3__order_status_enum.sql
V10__drop_legacy_columns.sql

Between any two versions, the diff highlights:

AddedNew tables, columns, enums, and references.
DroppedTables and columns removed by the migration.
ChangedColumn type changes and altered constraints.

Keyboard shortcuts

⌘ / Ctrl + SSave the current diagram.
TabIndent inside the editor.
⌘ / Ctrl + ZUndo.
Ready to design?
Jump back into the editor and start drawing.
Open editor