Skip to content

zoobz-io/erd

Repository files navigation

erd

CI Status codecov Go Report Card CodeQL Go Reference License Go Version Release

Go package for generating Entity Relationship Diagrams from domain models.

Domain as Diagram

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.

Installation

go get github.com/zoobz-io/erd

Example

Define 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
Loading

Struct Tags

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

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

Output Formats

Mermaid

mermaid := diagram.ToMermaid()

GraphViz DOT

dot := diagram.ToDOT()

Manual Construction

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))

Validation

errors := diagram.Validate()
for _, err := range errors {
    fmt.Println(err.Error())
}

Why erd?

  • 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

Documentation

  • API Reference - Complete API documentation
  • Sentinel - Type scanning library used for automatic extraction

Contributing

Contributions welcome. See CONTRIBUTING.md for development setup and guidelines.

License

MIT