Convert Mermaid ER to GORM (Go)
Generate production-ready GORM (Go) ORM code from your Mermaid ER diagrams in seconds.
π View the Roadmap to see which frameworks are coming next.
How the Mermaid ER to GORM (Go) conversion works
This pair leaves SQL entirely: the same Mermaid diagram that generates DDL becomes idiomatic Go β one struct per entity, gorm struct tags AutoMigrate understands, and a typed constant set for every ::ENUM directive so invalid states fail at compile time rather than at runtime.
Mermaid erDiagram is a Markdown-friendly notation rendered natively by GitHub, GitLab, Notion, and Obsidian β which makes it the most common way to keep an ER diagram next to the code it describes.
Entities are blocks of `type name marker` lines (markers: PK, FK, UK, INDEX), and relationships use cardinality arrows like `USER ||--o{ POST : writes` β one-to-many from USER to POST. The converter reads both, plus comment directives for everything the base syntax can't express.
Paste your Mermaid ER source into the editor above and the engine parses it into an
intermediate schema β tables, columns, relationships, indexes β then generates
GORM (Go) code from that model. Anything the diagram
syntax can't express (NOT NULL, defaults, enums, CHECK constraints, composite indexes)
you add with comment directives like %% ::NN, ::DEFAULT(now()) on the line
above a column. The Mermaid ER reference documents the
full vocabulary.
Worked example: an e-commerce schema
A complete Mermaid ER diagram and the exact GORM (Go) output the generator produces for it β different from the starter diagram in the editor above, so you can see a second real conversion end to end:
erDiagram
CUSTOMER ||--o{ ORDER : places
PRODUCT ||--o{ ORDER : "ordered in"
CUSTOMER {
int id PK
string email UK
%% ::NN
string name
%% ::DEFAULT(now())
timestamp created_at
}
PRODUCT {
int id PK
string sku UK
%% ::CHECK(price > 0)
decimal price
%% ::ENUM(draft, active, retired)
string status
}
ORDER {
int id PK
int customer_id FK
int product_id FK
%% ::DEFAULT(0)
decimal total
} package models
import (
"time"
)
type ProductStatus string
const (
ProductStatusDraft ProductStatus = "draft"
ProductStatusActive ProductStatus = "active"
ProductStatusRetired ProductStatus = "retired"
)
type Customer struct {
ID uint `gorm:"column:id;primaryKey" json:"id"`
Email *string `gorm:"column:email;uniqueIndex" json:"email"`
Name string `gorm:"column:name;not null" json:"name"`
CreatedAt *time.Time `gorm:"column:created_at;default:now()" json:"created_at"`
Orders []Order `gorm:"foreignKey:CustomerID" json:"orders,omitempty"`
}
type Order struct {
ID uint `gorm:"column:id;primaryKey" json:"id"`
CustomerID *uint `gorm:"column:customer_id" json:"customer_id"`
ProductID *uint `gorm:"column:product_id" json:"product_id"`
Total *float64 `gorm:"column:total;default:0" json:"total"`
Customer Customer `json:"customer,omitempty"`
Product Product `json:"product,omitempty"`
}
type Product struct {
ID uint `gorm:"column:id;primaryKey" json:"id"`
Sku *string `gorm:"column:sku;uniqueIndex" json:"sku"`
Price *float64 `gorm:"column:price" json:"price"`
Status *ProductStatus `gorm:"column:status;type:enum(draft,active,retired)" json:"status"`
Orders []Order `gorm:"foreignKey:ProductID" json:"orders,omitempty"`
} Nullability drives the Go types: name carried ::NN so it's a plain string, while email (nullable β UK doesn't imply NOT NULL) became *string. The enum emitted a ProductStatus type with three typed constants. Each relationship generated both sides β Customer.Orders []Order and Order.Customer Customer β plus the scalar CustomerID field GORM keys on.
What the generator emits for GORM (Go)
- one Go struct per table with exported PascalCase fields
- gorm struct tags: column names, primaryKey, uniqueness, not-null
- association fields for one-to-many, many-to-one, one-to-one, and many-to-many relationships
- ON DELETE constraint tags only when the diagram declares them β no surprise cascades
- json tags alongside the gorm tags, ready for API serialization
Type mapping: Mermaid ER to GORM (Go)
Diagram column types are logical β the generator maps each one to the idiomatic GORM (Go) type. These are the exact mappings the engine uses:
| Diagram type | GORM (Go) type | Notes |
|---|---|---|
int | uint | GORM's conventional PK type |
string | string | |
text | string | |
decimal | float64 | |
boolean | bool | |
date | time.Time | |
timestamp | time.Time | imports time automatically |
uuid | string | |
bigint | uint64 | |
blob | []byte |
Keys, relationships, and enums
`int id PK` becomes `ID uint` tagged `gorm:"primaryKey"` β the GORM convention that AutoMigrate recognizes as an auto-increment key. Nullable columns become pointer types (*string, *time.Time).
Each relationship generates both sides: the FK scalar field on the child, a parent navigation field (`User User`), and a slice on the parent (`Posts []Post`). Cascade tags are only added when the diagram explicitly sets onDelete.
`::ENUM(active, inactive)` generates a named Go string type with typed constants for each value, and the struct field uses that type β so invalid states fail at compile time, not at runtime.
Frequently asked questions
Why are some struct fields pointers and others plain values?
Pointers encode nullability. A column without ::NN (like email here) becomes *string so Go can represent NULL; a NOT NULL column becomes a value type. That's also why UK alone produced *string β unique doesn't mean required.
Can I run AutoMigrate on the generated structs directly?
Yes β the tags carry primaryKey, not null, uniqueIndex, column names, and defaults, which AutoMigrate reads as-is. If you prefer explicit SQL migrations, generate the postgres or mysql target from the same diagram instead; the two outputs describe the same schema.
Do the generated structs work with GORM AutoMigrate?
Yes β fields carry primaryKey, not-null, unique, and column tags that AutoMigrate reads directly. The same diagram can also generate plain SQL DDL if you prefer explicit migrations.
How are nullable columns represented in Go?
As pointer types: a nullable string becomes *string, a nullable timestamp *time.Time. Non-nullable columns use value types.