Skip to main content

Schema

.erd.json is the editor's document format. It is what editor.value returns, what setInitialValue() accepts, and what the JSON export writes — read this page if you need to generate, validate, or migrate a document outside the editor.

TypeScript​

ERDEditorSchemaV3​

type ERDEditorSchemaV3 = {
$schema: 'https://raw.githubusercontent.com/dineug/erd-editor/main/json-schema/schema.json';
version: '3.0.0';
settings: Settings;
doc: Doc;
collections: {
tableEntities: Record<string, Table>;
tableColumnEntities: Record<string, Column>;
relationshipEntities: Record<string, Relationship>;
indexEntities: Record<string, Index>;
indexColumnEntities: Record<string, IndexColumn>;
memoEntities: Record<string, Memo>;
};
};

Settings​

type Settings = {
width: number;
height: number;
scrollTop: number; // legacy, read once to migrate
scrollLeft: number; // legacy, read once to migrate
originX: number;
originY: number;
zoomLevel: number;
show: number; // Constants: Show
database: number; // Constants: Database
databaseName: string;
canvasType: string; // Constants: CanvasType
language: number; // Constants: Language
tableNameCase: number; // Constants: NameCase
columnNameCase: number; // Constants: NameCase
bracketType: number; // Constants: BracketType
relationshipDataTypeSync: boolean;
relationshipOptimization: boolean;
columnOrder: number[]; // Constants: ColumnType
maxWidthComment: number;
ignoreSaveSettings: number; // Constants: SaveSettingType
};

// Constants
const CanvasType = {
ERD: 'ERD',
visualization: '@dineug/erd-editor/builtin-visualization',
schemaSQL: '@dineug/erd-editor/builtin-schema-sql',
generatorCode: '@dineug/erd-editor/builtin-generator-code',
settings: 'settings',
} as const;

const Show = {
tableComment: 1,
columnComment: 2,
columnDataType: 4,
columnDefault: 8,
columnAutoIncrement: 16,
columnPrimaryKey: 32,
columnUnique: 64,
columnNotNull: 128,
relationship: 256,
columnAlternateKey: 512,
hideReferentialAction: 1024,
} as const;

const ColumnType = {
columnName: 1,
columnDataType: 2,
columnNotNull: 4,
columnUnique: 8,
columnAutoIncrement: 16,
columnDefault: 32,
columnComment: 64,
} as const;

const Database = {
MariaDB: 1,
MSSQL: 2,
MySQL: 4,
Oracle: 8,
PostgreSQL: 16,
SQLite: 32,
Databricks: 64,
Snowflake: 128,
} as const;

const Language = {
GraphQL: 1,
csharp: 2,
Java: 4,
Kotlin: 8,
TypeScript: 16,
JPA: 32,
Scala: 64,
Go: 128,
SQLAlchemy: 256,
TypeORM: 512,
Sequelize: 1024,
Drizzle: 2048,
DBML: 4096,
AML: 8192,
} as const;

const NameCase = {
none: 1,
camelCase: 2,
pascalCase: 4,
snakeCase: 8,
} as const;

const BracketType = {
none: 1,
doubleQuote: 2,
singleQuote: 4,
backtick: 8,
} as const;

const SaveSettingType = {
scroll: 1,
zoomLevel: 2,
} as const;

originX and originY are the view: the screen point scene (0, 0) lands on.
scrollTop and scrollLeft are the legacy pair every editor before 3.6.0 reads. The parser reads them once, and only when a document carries no origin, to derive originX and originY from them; nothing writes them any more. A document saved here therefore opens in an older editor where that editor last left it, rather than where this one saved it.
width and height are the legacy canvas size. The canvas is unbounded, so nothing sets them any longer; they are still written, at their defaults, for an older editor to read.
zoomLevel runs from 0.1 to 1.5. A document saved past 1 opens at 1 in an editor before 3.5.0.

canvasType is the tab a document opens on. A document saved on the Visualization tab holds '@dineug/erd-editor/builtin-visualization' but not whether Graph or Flow mode was showing, and a newly created editor shows that tab in Graph mode.
None of Flow mode's own state is serialized — its placement, zoom, pan, row display and focused tables stay in the editor — so originX, originY and zoomLevel always describe the ERD canvas.

show and ignoreSaveSettings are bitmasks — OR the flags together.
columnOrder is an array holding all seven ColumnType values, in display order.
database, language, tableNameCase, columnNameCase and bracketType each hold exactly one value, and the JSON Schema rejects a combined value.

A new document's show is 431: tableComment, columnComment, columnDataType, columnDefault, columnPrimaryKey, columnNotNull and relationship.
Since 3.10.0 there are two more show flags, both off in a new document and in every document saved before 3.10.0.
columnAlternateKey (512) is the Alternate Key view option. Set, it marks the columns of each unique index over two or more columns as AK1.1, AK1.2 and so on. It starts off, so no existing diagram changes width.
hideReferentialAction (1024) is the one flag that hides what it names: set, it hides the ON DELETE and ON UPDATE labels on connectors, so they show by default. The Referential Actions view option is checked while the flag is off. It changes no table's size.
An editor before 3.10.0 keeps show as a whole number, so both flags survive a save there.

ignoreSaveSettings leaves the view out of the written document. With scroll set, originX and originY are written as 0; with zoomLevel set, zoomLevel is written as 1. These are the Save Scroll Information and Save Zoom Information settings, each on while its bit is clear. A zoom moves the origin as well, so with only zoomLevel set a zoom still changes the written document.
Since 3.10.0 a document started from nothing — a new editor or replication store, or a blank value given to value or setInitialValue() — has ignoreSaveSettings set to 3, so it saves neither. A document whose settings carries no ignoreSaveSettings, such as one saved before 3.2.3, still reads as 0 and saves both, as the release that wrote it did.

Database, Language, Show and ReferentialAction are append-only. A saved document stores the number, so a new vendor, code-generation target, flag or action takes the next bit instead of a slot in the middle.

Doc​

type Doc = {
tableIds: string[];
relationshipIds: string[];
indexIds: string[];
memoIds: string[];
};

EntityType​

Every entity in collections carries a meta object.

type EntityMeta = {
updateAt: number;
createAt: number;
};

type EntityType<T> = T & {
meta: EntityMeta;
};

Collection: tableEntities​

type Table = EntityType<{
id: string;
name: string;
comment: string;
columnIds: string[];
seqColumnIds: string[];
ui: TableUI;
}>;

type TableUI = {
x: number;
y: number;
zIndex: number;
widthName: number;
widthComment: number;
color: string;
};

Collection: tableColumnEntities​

type Column = EntityType<{
id: string;
tableId: string;
name: string;
comment: string;
dataType: string;
default: string;
options: number; // Constants: ColumnOption
ui: ColumnUI;
}>;

type ColumnUI = {
keys: number; // Constants: ColumnUIKey
widthName: number;
widthComment: number;
widthDataType: number;
widthDefault: number;
};

// Constants
const ColumnOption = {
autoIncrement: 1,
primaryKey: 2,
unique: 4,
notNull: 8,
} as const;

const ColumnUIKey = {
primaryKey: 1,
foreignKey: 2,
} as const;

Collection: relationshipEntities​

type Relationship = EntityType<{
id: string;
identification: boolean;
relationshipType: number; // Constants: RelationshipType
startRelationshipType: number; // Constants: StartRelationshipType
onDelete: number; // Constants: ReferentialAction
onUpdate: number; // Constants: ReferentialAction
start: RelationshipPoint;
end: RelationshipPoint;
}>;

type RelationshipPoint = {
tableId: string;
columnIds: string[];
x: number;
y: number;
direction: number; // Constants: Direction
};

// Constants
const RelationshipType = {
ZeroOne: 2,
ZeroN: 4,
OneOnly: 8,
OneN: 16,
} as const;

const StartRelationshipType = {
ring: 1,
dash: 2,
} as const;

const ReferentialAction = {
none: 1,
noAction: 2,
cascade: 4,
setNull: 8,
setDefault: 16,
restrict: 32,
} as const;

const Direction = {
left: 1,
right: 2,
top: 4,
bottom: 8,
} as const;

Since 3.10.0 a relationship carries onDelete and onUpdate, its ON DELETE and ON UPDATE actions. Each holds exactly one ReferentialAction value. none, the default, writes no clause, so the database's own default applies. The other five stand for NO ACTION, CASCADE, SET NULL, SET DEFAULT and RESTRICT. Schema SQL writes a clause only for a database that accepts its action.
Both fields are optional. A missing field, as in every document saved before 3.10.0, reads as none, and so does a value outside the list; the JSON Schema checks only that each is an integer.
An editor before 3.10.0 does not know the fields and drops them when it loads a document, so saving there loses every action.

Collection: indexEntities​

type Index = EntityType<{
id: string;
name: string;
tableId: string;
indexColumnIds: string[];
seqIndexColumnIds: string[];
unique: boolean;
}>;

Collection: indexColumnEntities​

type IndexColumn = EntityType<{
id: string;
indexId: string;
columnId: string;
orderType: number; // Constants: OrderType
}>;

// Constants
const OrderType = {
ASC: 1,
DESC: 2,
} as const;

Collection: memoEntities​

type Memo = EntityType<{
id: string;
value: string;
ui: MemoUI;
}>;

type MemoUI = {
x: number;
y: number;
width: number;
height: number;
zIndex: number;
color: string;
};

JSON Schema​

The canonical schema file is published at json-schema/schema.json and can be referenced directly with $schema.

{
"$schema": "https://raw.githubusercontent.com/dineug/erd-editor/main/json-schema/schema.json",
"version": "3.0.0"
}

Put $schema at the top of an .erd.json file and editors that understand JSON Schema, such as VS Code, validate the document and autocomplete its fields as you edit.

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/dineug/erd-editor/main/json-schema/schema.json",
"title": "erd-editor schema",
"description": "Entity-Relationship Diagram Editor Schema",
"type": "object",
"properties": {
"$schema": {
"type": "string"
},
"version": {
"description": "Version of the schema",
"const": "3.0.0"
},
"settings": {
"$ref": "#/$defs/settings"
},
"doc": {
"$ref": "#/$defs/doc"
},
"collections": {
"type": "object",
"properties": {
"tableEntities": {
"$ref": "#/$defs/tableEntities"
},
"tableColumnEntities": {
"$ref": "#/$defs/tableColumnEntities"
},
"relationshipEntities": {
"$ref": "#/$defs/relationshipEntities"
},
"indexEntities": {
"$ref": "#/$defs/indexEntities"
},
"indexColumnEntities": {
"$ref": "#/$defs/indexColumnEntities"
},
"memoEntities": {
"$ref": "#/$defs/memoEntities"
}
},
"required": [
"tableEntities",
"tableColumnEntities",
"relationshipEntities",
"indexEntities",
"indexColumnEntities",
"memoEntities"
]
}
},
"required": ["version", "settings", "doc", "collections"],
"$defs": {
"settings": {
"type": "object",
"properties": {
"width": {
"type": "number",
"minimum": 2000,
"maximum": 20000
},
"height": {
"type": "number",
"minimum": 2000,
"maximum": 20000
},
"scrollTop": {
"type": "number"
},
"scrollLeft": {
"type": "number"
},
"originX": {
"type": "number"
},
"originY": {
"type": "number"
},
"zoomLevel": {
"type": "number",
"minimum": 0.1,
"maximum": 1.5
},
"show": {
"description": "bit value (tableComment: 1) | (columnComment: 2) | (columnDataType: 4) | (columnDefault: 8) | (columnAutoIncrement: 16) | (columnPrimaryKey: 32) | (columnUnique: 64) | (columnNotNull: 128) | (relationship: 256) | (columnAlternateKey: 512) | (hideReferentialAction: 1024)",
"type": "integer"
},
"database": {
"description": "bit value (MariaDB: 1) | (MSSQL: 2) | (MySQL: 4) | (Oracle: 8) | (PostgreSQL: 16) | (SQLite: 32) | (Databricks: 64) | (Snowflake: 128)",
"type": "integer",
"enum": [1, 2, 4, 8, 16, 32, 64, 128]
},
"databaseName": {
"type": "string"
},
"canvasType": {
"enum": [
"ERD",
"@dineug/erd-editor/builtin-visualization",
"@dineug/erd-editor/builtin-schema-sql",
"@dineug/erd-editor/builtin-generator-code",
"settings"
]
},
"language": {
"description": "bit value (GraphQL: 1) | (csharp: 2) | (Java: 4) | (Kotlin: 8) | (TypeScript: 16) | (JPA: 32) | (Scala: 64) | (Go: 128) | (SQLAlchemy: 256) | (TypeORM: 512) | (Sequelize: 1024) | (Drizzle: 2048) | (DBML: 4096) | (AML: 8192)",
"type": "integer",
"enum": [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192]
},
"tableNameCase": {
"description": "bit value (none: 1) | (camelCase: 2) | (pascalCase: 4) | (snakeCase: 8)",
"type": "integer",
"enum": [1, 2, 4, 8]
},
"columnNameCase": {
"description": "bit value (none: 1) | (camelCase: 2) | (pascalCase: 4) | (snakeCase: 8)",
"type": "integer",
"enum": [1, 2, 4, 8]
},
"bracketType": {
"description": "bit value (none: 1) | (doubleQuote: 2) | (singleQuote: 4) | (backtick: 8)",
"type": "integer",
"enum": [1, 2, 4, 8]
},
"relationshipDataTypeSync": {
"type": "boolean"
},
"relationshipOptimization": {
"type": "boolean"
},
"columnOrder": {
"description": "bit value (columnName: 1) | (columnDataType: 2) | (columnNotNull: 4) | (columnUnique: 8) | (columnAutoIncrement: 16) | (columnDefault: 32) | (columnComment: 64)",
"type": "array",
"prefixItems": [
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" },
{ "type": "integer" }
],
"minItems": 7,
"maxItems": 7
},
"maxWidthComment": {
"type": "integer"
},
"ignoreSaveSettings": {
"description": "bit value (scroll: 1) | (zoomLevel: 2)",
"type": "integer"
}
},
"required": [
"width",
"height",
"scrollTop",
"scrollLeft",
"zoomLevel",
"show",
"canvasType",
"language",
"tableNameCase",
"columnNameCase",
"bracketType",
"relationshipDataTypeSync",
"relationshipOptimization",
"columnOrder",
"maxWidthComment"
]
},
"doc": {
"type": "object",
"properties": {
"tableIds": {
"type": "array",
"items": {
"type": "string"
}
},
"relationshipIds": {
"type": "array",
"items": {
"type": "string"
}
},
"indexIds": {
"type": "array",
"items": {
"type": "string"
}
},
"memoIds": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"tableEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"comment": {
"type": "string"
},
"columnIds": {
"type": "array",
"items": {
"type": "string"
}
},
"seqColumnIds": {
"type": "array",
"items": {
"type": "string"
}
},
"ui": {
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"zIndex": {
"type": "number"
},
"widthName": {
"type": "number"
},
"widthComment": {
"type": "number"
},
"color": {
"type": "string"
}
},
"required": [
"x",
"y",
"zIndex",
"widthName",
"widthComment",
"color"
]
},
"meta": {
"$ref": "#/$defs/EntityMeta"
}
},
"required": [
"id",
"name",
"comment",
"columnIds",
"seqColumnIds",
"ui",
"meta"
]
}
},
"tableColumnEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"tableId": {
"type": "string"
},
"name": {
"type": "string"
},
"comment": {
"type": "string"
},
"dataType": {
"type": "string"
},
"default": {
"type": "string"
},
"options": {
"description": "bit value (autoIncrement: 1) | (primaryKey: 2) | (unique: 4) | (notNull: 8)",
"type": "integer"
},
"ui": {
"type": "object",
"properties": {
"keys": {
"description": "bit value (primaryKey: 1) | (foreignKey: 2)",
"type": "integer"
},
"widthName": {
"type": "number"
},
"widthComment": {
"type": "number"
},
"widthDataType": {
"type": "number"
},
"widthDefault": {
"type": "number"
}
},
"required": [
"keys",
"widthName",
"widthComment",
"widthDataType",
"widthDefault"
]
},
"meta": {
"$ref": "#/$defs/EntityMeta"
}
},
"required": [
"id",
"tableId",
"name",
"comment",
"dataType",
"default",
"options",
"ui",
"meta"
]
}
},
"relationshipEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"identification": {
"type": "boolean"
},
"relationshipType": {
"description": "bit value (ZeroOne: 2) | (ZeroN: 4) | (OneOnly: 8) | (OneN: 16)",
"type": "integer"
},
"startRelationshipType": {
"description": "bit value (ring: 1) | (dash: 2)",
"type": "integer"
},
"onDelete": {
"description": "bit value (none: 1) | (noAction: 2) | (cascade: 4) | (setNull: 8) | (setDefault: 16) | (restrict: 32); none, the default, writes no ON DELETE clause",
"type": "integer"
},
"onUpdate": {
"description": "bit value (none: 1) | (noAction: 2) | (cascade: 4) | (setNull: 8) | (setDefault: 16) | (restrict: 32); none, the default, writes no ON UPDATE clause",
"type": "integer"
},
"start": {
"$ref": "#/$defs/RelationshipPoint"
},
"end": {
"$ref": "#/$defs/RelationshipPoint"
},
"meta": {
"$ref": "#/$defs/EntityMeta"
}
},
"required": [
"id",
"identification",
"relationshipType",
"startRelationshipType",
"start",
"end",
"meta"
]
}
},
"indexEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"tableId": {
"type": "string"
},
"indexColumnIds": {
"type": "array",
"items": {
"type": "string"
}
},
"seqIndexColumnIds": {
"type": "array",
"items": {
"type": "string"
}
},
"unique": {
"type": "boolean"
},
"meta": {
"$ref": "#/$defs/EntityMeta"
}
},
"required": [
"id",
"name",
"tableId",
"indexColumnIds",
"seqIndexColumnIds",
"unique",
"meta"
]
}
},
"indexColumnEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"indexId": {
"type": "string"
},
"columnId": {
"type": "string"
},
"orderType": {
"description": "bit value (ASC: 1) | (DESC: 2)",
"type": "integer"
},
"meta": {
"$ref": "#/$defs/EntityMeta"
}
},
"required": ["id", "indexId", "columnId", "orderType", "meta"]
}
},
"memoEntities": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"value": {
"type": "string"
},
"ui": {
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"zIndex": {
"type": "number"
},
"width": {
"type": "number"
},
"height": {
"type": "number"
},
"color": {
"type": "string"
}
},
"required": ["x", "y", "zIndex", "width", "height", "color"]
},
"meta": {
"$ref": "#/$defs/EntityMeta"
}
},
"required": ["id", "value", "ui", "meta"]
}
},
"EntityMeta": {
"type": "object",
"properties": {
"updateAt": {
"type": "integer"
},
"createAt": {
"type": "integer"
}
},
"required": ["updateAt", "createAt"]
},
"RelationshipPoint": {
"type": "object",
"properties": {
"tableId": {
"type": "string"
},
"columnIds": {
"type": "array",
"items": {
"type": "string"
}
},
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"direction": {
"description": "bit value (left: 1) | (right: 2) | (top: 4) | (bottom: 8)",
"type": "integer"
}
},
"required": ["tableId", "columnIds", "x", "y", "direction"]
}
}
}