erdn-lang is a lightweight domain-specific language for describing Entity-Relationship Diagrams (ERDs). Write a plain-text .erdn schema file, render a clean SVG diagram, and export SQL DDL — no GUI required.
Maintaining ERD diagrams is tedious: graphical tools produce binary files that are hard to diff, and hand-rolled diagrams drift out of sync with real schemas. erdn-lang solves this by letting you describe your schema as code:
- Text-based — store
.erdnfiles alongside your source code and track changes in version control. - SQL export ready — generate SQL DDL from the same schema for MySQL, PostgreSQL, SQL Server, Oracle, and SQLite.
- Validated — the
validatecommand catches semantic errors (unknown tables, duplicate keys, conflicting modifiers) before you render. - Readable —
#comments on tables, columns, and links are rendered as subtitle rows directly in the diagram.
You need Go 1.21 or later.
# CLI tool
go install github.com/headercat/erdn-lang/cmd/erdn@latest
# MCP server
go install github.com/headercat/erdn-lang/cmd/erdn-mcp@latestgit clone https://github.com/headercat/erdn-lang.git
cd erdn-lang
go build -o erdn ./cmd/erdnerdn render <schema.erdn> [--out <file.svg>]
erdn validate <schema.erdn>
erdn sql <schema.erdn> [--dbms <mysql|postgresql|mssql|oracle|sqlite>] [--out <file.sql>]
Parses and validates the schema, then writes an SVG diagram.
# Output written to schema.svg by default
erdn render schema.erdn
# Specify a custom output path
erdn render schema.erdn --out diagrams/schema.svgChecks the schema for parse and semantic errors without producing any output file. Exits with a non-zero status code if errors are found.
erdn validate schema.erdn
# OKGenerates SQL DDL (CREATE TABLE, indexes, and foreign key constraints) from the schema. Use --dbms to target a specific database engine (default: mysql).
| DBMS | Flag value |
|---|---|
| MySQL | mysql |
| PostgreSQL | postgresql |
| Microsoft SQL Server | mssql |
| Oracle Database | oracle |
| SQLite | sqlite |
# Output written to schema.sql by default (MySQL)
erdn sql schema.erdn
# Target PostgreSQL
erdn sql schema.erdn --dbms postgresql
# Specify a custom output path
erdn sql schema.erdn --dbms mssql --out migrations/001_init.sqlerdn-lang ships a local Model Context Protocol server so AI assistants and MCP-compatible editors can convert SQL schemas to ERDN and generate diagrams.
go install github.com/headercat/erdn-lang/cmd/erdn-mcp@latest{
"mcpServers": {
"erdn-lang": {
"type": "stdio",
"command": "go",
"args": ["run", "github.com/headercat/erdn-lang/cmd/erdn-mcp@latest"]
}
}
}Copy this block into your MCP client's configuration file, or use the .mcp.json at the root of this repository if your client supports auto-discovery.
If you have already run go install above, you can replace the "command"/"args" with the installed binary:
{
"mcpServers": {
"erdn-lang": {
"type": "stdio",
"command": "erdn-mcp"
}
}
}If you do have a local clone you can also run the server directly:
go run ./cmd/erdn-mcpThe server exposes two tools:
convert_sql_to_erdn— converts SQLCREATE TABLE/FOREIGN KEYschema text into ERDN source.generate_svg_from_erdn— validates ERDN and returns generated SVG diagram text.
The generated SQL includes:
CREATE TABLEstatements with DBMS-appropriate types and constraints.PRIMARY KEYconstraints.AUTO_INCREMENT/IDENTITY(1,1)/GENERATED ALWAYS AS IDENTITYfor auto-increment columns.CREATE INDEXstatements forindexedcolumns.ALTER TABLE … ADD CONSTRAINT … FOREIGN KEYstatements derived fromlinkdeclarations (inlineFOREIGN KEYfor SQLite).
An erdn-lang file is made up of comments, table definitions, and link declarations. Order does not matter — links may be declared before the tables they reference.
Two comment styles are supported:
| Style | Syntax | Rendered in diagram? |
|---|---|---|
| Hash comment | # text |
✅ Yes — shown as a subtitle row |
| Line comment | // text |
❌ No — ignored by the renderer |
# This comment appears in the SVG as a subtitle
// This comment is invisible in the diagram
table <name> (
<columns…>
)
A # comment placed immediately before the opening parenthesis (or as the first line inside the body) becomes the table's subtitle in the diagram.
# Stores registered user accounts
table users (
id bigint primary-key auto-increment
name varchar(255) not-null
)
<name> <type>[(<param>, …)] [modifiers…]
- name — any identifier (letters, digits,
_). - type — any identifier, e.g.
bigint,varchar,text,timestamp,bool,int,char. - type params — optional comma-separated values in parentheses, e.g.
varchar(255),char(2).
id bigint primary-key auto-increment
username varchar(64) not-null indexed
bio text nullable
created_at timestamp not-null default(NOW())
A # comment on the line immediately above a column is rendered as the column's annotation in the diagram.
| Modifier | Description |
|---|---|
primary-key |
Marks the column as the primary key (at most one per table). |
auto-increment |
Column value is auto-incremented by the database. |
not-null |
Column must not contain NULL values. |
nullable |
Column explicitly allows NULL values. |
indexed |
Column has a database index. |
default(<value>) |
Specifies a default value expression. |
nullableandnot-nullare mutually exclusive on the same column.
Links declare a directed relationship between two columns in (possibly different) tables.
[# comment]
link <from-cardinality> <table>.<column> to <to-cardinality> <table>.<column>
- Cardinality is either
oneormany. - The source side (
from) is typicallyone; the destination side (to) is typicallymany. - Self-referential links (a table linking to itself) are supported.
- Links may be placed anywhere in the file — before or after the tables they reference.
# One author writes many posts
link one authors.id to many posts.author_id
# Self-referential: a category can have sub-categories
link one categories.id to many categories.parent_id
# A simple blog schema
table authors (
# Unique identifier for each author
id bigint primary-key auto-increment
username varchar(64) not-null indexed
email varchar(255) not-null indexed
bio text nullable
)
table posts (
# One row per published article
id bigint primary-key auto-increment
author_id bigint not-null indexed
title varchar(512) not-null
body text not-null
# draft, published, archived
status varchar(32) not-null default("draft")
created_at timestamp not-null default(NOW())
)
# An author can write many posts
link one authors.id to many posts.author_id
Render it:
erdn render blog.erdn
# rendered blog.svgMore examples are available in the examples/ directory.
Contributions are welcome! To get started:
- Fork the repository and create a feature branch.
- Make your changes and add or update tests where appropriate.
- Run
go test ./...to verify everything passes. - Open a pull request describing what you changed and why.
Please keep pull requests focused — one feature or fix per PR.
This project is licensed under the MIT License.
Copyright (c) 2026 Headercat Inc.