Go package for generating Entity Relationship Diagrams from domain models.
Your Go structs already define your domain. ERD extracts that structure and renders it as visual documentation that stays in sync with your code.
type User struct {
ID string `erd:"pk"`
Profile *Profile // one-to-one
Orders []Order // one-to-many
}The relationships live in your types. ERD makes them visible.
go get github.com/zoobz-io/erdDefine your domain models with erd struct tags:
package main
import (
"fmt"
"github.com/zoobz-io/erd"
"github.com/zoobz-io/sentinel"
)
type User struct {
ID string `erd:"pk"`
Email string `erd:"uk"`
Name string
Profile *Profile
Orders []Order
}
type Profile struct {
ID string `erd:"pk"`
Bio *string
Avatar *string `erd:"note:Profile picture URL"`
}
type Order struct {
ID string `erd:"pk"`
UserID string `erd:"fk"`
Total float64
Status string
}
func main() {
// Scan types to extract metadata
sentinel.Scan[User]()
// Generate ERD from schema
diagram := erd.FromSchema("User Domain", sentinel.Schema())
// Output as Mermaid
fmt.Println(diagram.ToMermaid())
}This produces the following diagram:
erDiagram
Order {
string ID PK
string UserID FK
float64 Total
string Status
}
Profile {
string ID PK
string Bio "nullable"
string Avatar "nullable, Profile picture URL"
}
User {
string ID PK
string Email UK
string Name
}
User ||--|| Profile : Profile
User ||--o{ Order : Orders
The erd tag supports:
| Tag | Description |
|---|---|
pk |
Primary key |
fk |
Foreign key |
uk |
Unique key |
note:... |
Attribute note |
Tags can be combined: erd:"pk,note:Auto-generated UUID"
Relationships are inferred from struct fields:
| Field Type | Cardinality |
|---|---|
*T (pointer) |
One-to-one |
[]T (slice) |
One-to-many |
T (embedded) |
One-to-one |
map[K]V |
Many-to-many |
mermaid := diagram.ToMermaid()dot := diagram.ToDOT()For cases where you need more control:
diagram := erd.NewDiagram("E-commerce").
WithDescription("Shopping cart domain model")
product := erd.NewEntity("Product").
AddAttribute(erd.NewAttribute("ID", "string").WithPrimaryKey()).
AddAttribute(erd.NewAttribute("Name", "string")).
AddAttribute(erd.NewAttribute("Price", "float64"))
cart := erd.NewEntity("Cart").
AddAttribute(erd.NewAttribute("ID", "string").WithPrimaryKey()).
AddAttribute(erd.NewAttribute("UserID", "string").WithForeignKey())
diagram.
AddEntity(product).
AddEntity(cart).
AddRelationship(erd.NewRelationship("Cart", "Product", "Items", erd.ManyToMany))errors := diagram.Validate()
for _, err := range errors {
fmt.Println(err.Error())
}- Type-driven: Relationships inferred from Go types, not annotations
- Two modes: Automatic via sentinel, or manual builder API
- Multiple formats: Mermaid for browsers, DOT for print-quality output
- Zero config: Works out of the box with standard Go structs
- Validation: Catches structural errors before rendering
- API Reference - Complete API documentation
- Sentinel - Type scanning library used for automatic extraction
Contributions welcome. See CONTRIBUTING.md for development setup and guidelines.
MIT