EF Core D2 database diagram
Create a readable D2 entity-relationship diagram that reflects the actual EF Core persistence model, not only raw C# class shape. Generate .d2 source and, when possible, validate and render it with the d2 CLI to SVG/PNG. Keep installed package layouts centered on SKILL.md; if documenting installation, mention SKILL.md plus references. SVG/PNG.
When to invoke
- "Generate a D2 database diagram from EF Core entities."
- "Create an ERD from this DbContext."
- "Visualize tables, columns, primary keys, foreign keys, and relationships."
- "Analyze DbSet, IEntityTypeConfiguration, Fluent API, and migrations."
- "Produce a .d2 file renderable to SVG or PNG."
Prerequisites and context
- Use the
d2 CLI when available: d2 input.d2 output.svg, d2 --layout=elk input.d2 output.svg, and d2 fmt input.d2.
- No MCP server is required; the skill generates D2 source code as text.
- Ask the diagram questionnaire before generation or regeneration unless the user already answered it in the same request.
Diagram questionnaire
Ask every question for new diagrams and regenerations. For quick generation, use the defaults.
| Question |
Default |
Which DbContext should be diagrammed? (auto-detect/all/specific name) |
auto-detect |
Display columns? (all/key-only/none) |
key-only |
Display column types? (Yes/No) |
Yes |
Display nullable/required markers? (Yes/No) |
Yes |
Required/optional relationship notation? (Yes/No) |
Yes |
Display indexes and unique constraints? (Yes/No) |
Yes |
Display enum values? (Yes/No) |
No |
Display owned types? (inline/separate/hide) |
inline |
Display many-to-many join tables? (explicit/compact/hide) |
explicit |
Display audit/technical tables? (Yes/No) |
No |
Audit/technical table summary? (Yes/No) |
Yes |
Display migration-only tables not present as entities? (Yes/No) |
Yes |
Which grouping mode? (bounded-context/schema/namespace/flat) |
bounded-context |
Which layout engine? (elk/dagre/tala) |
elk |
Which output format? (d2/svg/png) |
d2 |
EF Core extraction rules
Use this source priority when sources disagree:
- Latest applied migration / migration snapshot.
- Fluent API configuration in
OnModelCreating or IEntityTypeConfiguration<T>.
- Data annotations.
- EF Core conventions.
- Raw C# class shape.
Detect and represent these EF Core concepts:
| Concept |
Required extraction |
| Context and entities |
DbContext, DbSet<T>, entity class names, actual table names from ToTable, schema names from ToTable("Table", "schema"). |
| Keys |
Primary keys from HasKey, [Key], conventions, migrations, composite keys, and HasAlternateKey. |
| Relationships |
Foreign keys from HasForeignKey, navigation properties, migration operations, required/optional markers, and delete behavior: Cascade, Restrict, NoAction, SetNull, ClientSetNull. |
| Owned/value objects |
OwnsOne, OwnsMany, [Owned], inline/separate/hide rendering choice. |
| Many-to-many |
UsingEntity and implicit EF Core join tables; default to explicit join tables. |
| Constraints and columns |
HasIndex, IsUnique, shadow properties, value conversions, enum properties, ignored properties, and ignored entities. |
D2 rendering rules
Represent each persisted table as a D2 node with shape: sql_table when possible.
Clients: {
shape: sql_table
constraint: primary_key
Id: uuid {constraint: primary_key}
Name: text
Status: enum
}
If sql_table is unavailable or causes validation issues, use a rectangle with structured text. Draw directional edges from dependent table to principal table, and include cardinality and FK name when known.
Offers.ClientId -> Clients.Id: "N:1 FK_Offers_Clients_ClientId"
Use cardinality labels 1:1, 1:N, N:1, N:N, and owned. Required relationships use solid lines; optional relationships use dashed lines; cascade delete labels end with cascade.
Owned types default to inline rendering:
Clients: {
shape: sql_table
Id: uuid {constraint: primary_key}
Address.Street: text
Address.ZipCode: text
Address.City: text
}
When the user chooses separate, represent owned types as visually subordinate tables and use an owned relationship. For implicit many-to-many relationships, create a generated join table node and mark it as implicit join.
Grouping and style
| Mode |
Rule |
bounded-context |
Group by detected domain area or folder/module. |
schema |
Group by database schema such as public, auth, or billing. |
namespace |
Group by C# namespace. |
flat |
Use no containers; all tables at the same level. |
| Element |
Style |
| Primary entity tables |
Solid border. |
| Join tables |
Dashed border. |
| Owned types |
Lighter stroke or nested inline fields. |
| Technical tables |
Muted style. |
| External or migration-only tables |
Dotted border. |
Hide technical tables by default unless requested. Examples include __EFMigrationsHistory, Hangfire tables, ASP.NET Identity tables, audit logs, and outbox tables. If hidden, list them in the summary.
Procedure
- Read the EF Core project structure.
- Locate all
DbContext classes.
- Locate all
DbSet<T> declarations.
- Locate entity classes, owned types, enum types, and value objects.
- Read
OnModelCreating and all IEntityTypeConfiguration<T> classes.
- Read migrations when available to confirm table names, join tables, indexes, and delete behaviors.
- Build a normalized database model before writing D2.
- Ask the mandatory diagram questionnaire before generation.
- Generate the
.d2 file from the database model, not raw class nesting.
- Validate D2 syntax with
d2 fmt before delivery.
- Render with
d2 --layout=elk schema.d2 schema.svg when possible.
- If regenerating, re-read EF Core mappings and migrations first.
Progressive disclosure and bundled resources
Load bundled references on demand:
references/efcore-model-extraction.md: rules for reading DbContext, DbSet, Fluent API, configurations, and migrations.
references/d2-erd-style.md: D2 syntax and visual conventions for ERD diagrams.
references/relationship-rules.md: how to infer one-to-one, one-to-many, many-to-many, and owned relationships.
references/grouping-modes.md: rules for bounded-context, schema, namespace, and flat grouping.
references/quality-gate.md: final checklist before delivering the generated diagram.
Output template
## EF Core D2 diagram — <DbContext or scope>
**Status:** generated | needs answers | blocked
**Selected DbContext:** <auto-detect/all/name>
**Output format:** d2 | svg | png
**Layout:** elk | dagre | tala
### D2 source
```d2
<schema.d2 content>
```
### Render command
```bash
d2 --layout=elk schema.d2 schema.svg
```
### Assumptions and hidden tables
- Columns: all | key-only | none
- Owned types: inline | separate | hide
- Many-to-many join tables: explicit | compact | hide
- Hidden technical tables: `__EFMigrationsHistory`, <others or none>
### Validation
- `d2 fmt schema.d2`: pass | fail | not run
- EF Core mappings read: migrations, Fluent API, annotations, conventions
Quality gate
1---2name: efcore-d2-db-diagram-23description: Generates D2 entity-relationship diagrams from Entity Framework Core models by extracting DbContext, DbSet<T>, entity configuration, migrations, keys, foreign keys, owned types, many-to-many joins, indexes, schemas, and technical tables. Use this skill when asked to generate a database diagram, ERD, .d2 file, SVG, or PNG from an EF Core or ASP.NET Core codebase.4---56# EF Core D2 database diagram78Create a readable D2 entity-relationship diagram that reflects the actual EF Core persistence model, not only raw C# class shape. Generate `.d2` source and, when possible, validate and render it with the `d2` CLI to `SVG/PNG`. Keep installed package layouts centered on `SKILL.md`; if documenting installation, mention `SKILL.md` plus references. SVG/PNG.910## When to invoke1112- "Generate a D2 database diagram from EF Core entities."13- "Create an ERD from this DbContext."14- "Visualize tables, columns, primary keys, foreign keys, and relationships."15- "Analyze DbSet<T>, IEntityTypeConfiguration<T>, Fluent API, and migrations."16- "Produce a .d2 file renderable to SVG or PNG."1718## Prerequisites and context1920- Use the `d2` CLI when available: `d2 input.d2 output.svg`, `d2 --layout=elk input.d2 output.svg`, and `d2 fmt input.d2`.21- No MCP server is required; the skill generates D2 source code as text.22- Ask the diagram questionnaire before generation or regeneration unless the user already answered it in the same request.2324## Diagram questionnaire2526Ask every question for new diagrams and regenerations. For quick generation, use the defaults.2728| Question | Default |29| --- | --- |30| `Which DbContext should be diagrammed? (auto-detect/all/specific name)` | `auto-detect` |31| `Display columns? (all/key-only/none)` | `key-only` |32| `Display column types? (Yes/No)` | `Yes` |33| `Display nullable/required markers? (Yes/No)` | `Yes` |34| `Required/optional relationship notation? (Yes/No)` | `Yes` |35| `Display indexes and unique constraints? (Yes/No)` | `Yes` |36| `Display enum values? (Yes/No)` | `No` |37| `Display owned types? (inline/separate/hide)` | `inline` |38| `Display many-to-many join tables? (explicit/compact/hide)` | `explicit` |39| `Display audit/technical tables? (Yes/No)` | `No` |40| `Audit/technical table summary? (Yes/No)` | `Yes` |41| `Display migration-only tables not present as entities? (Yes/No)` | `Yes` |42| `Which grouping mode? (bounded-context/schema/namespace/flat)` | `bounded-context` |43| `Which layout engine? (elk/dagre/tala)` | `elk` |44| `Which output format? (d2/svg/png)` | `d2` |4546## EF Core extraction rules4748Use this source priority when sources disagree:49501. Latest applied migration / migration snapshot.512. Fluent API configuration in `OnModelCreating` or `IEntityTypeConfiguration<T>`.523. Data annotations.534. EF Core conventions.545. Raw C# class shape.5556Detect and represent these EF Core concepts:5758| Concept | Required extraction |59| --- | --- |60| Context and entities | `DbContext`, `DbSet<T>`, entity class names, actual table names from `ToTable`, schema names from `ToTable("Table", "schema")`. |61| Keys | Primary keys from `HasKey`, `[Key]`, conventions, migrations, composite keys, and `HasAlternateKey`. |62| Relationships | Foreign keys from `HasForeignKey`, navigation properties, migration operations, required/optional markers, and delete behavior: `Cascade`, `Restrict`, `NoAction`, `SetNull`, `ClientSetNull`. |63| Owned/value objects | `OwnsOne`, `OwnsMany`, `[Owned]`, inline/separate/hide rendering choice. |64| Many-to-many | `UsingEntity` and implicit EF Core join tables; default to explicit join tables. |65| Constraints and columns | `HasIndex`, `IsUnique`, shadow properties, value conversions, enum properties, ignored properties, and ignored entities. |6667## D2 rendering rules6869Represent each persisted table as a D2 node with `shape: sql_table` when possible.7071```d272Clients: {73 shape: sql_table74 constraint: primary_key75 Id: uuid {constraint: primary_key}76 Name: text77 Status: enum78}79```8081If `sql_table` is unavailable or causes validation issues, use a rectangle with structured text. Draw directional edges from dependent table to principal table, and include cardinality and FK name when known.8283```d284Offers.ClientId -> Clients.Id: "N:1 FK_Offers_Clients_ClientId"85```8687Use cardinality labels `1:1`, `1:N`, `N:1`, `N:N`, and `owned`. Required relationships use solid lines; optional relationships use dashed lines; cascade delete labels end with `cascade`.8889Owned types default to inline rendering:9091```d292Clients: {93 shape: sql_table94 Id: uuid {constraint: primary_key}95 Address.Street: text96 Address.ZipCode: text97 Address.City: text98}99```100101When the user chooses `separate`, represent owned types as visually subordinate tables and use an `owned` relationship. For implicit many-to-many relationships, create a generated join table node and mark it as `implicit join`.102103## Grouping and style104105| Mode | Rule |106| --- | --- |107| `bounded-context` | Group by detected domain area or folder/module. |108| `schema` | Group by database schema such as `public`, `auth`, or `billing`. |109| `namespace` | Group by C# namespace. |110| `flat` | Use no containers; all tables at the same level. |111112| Element | Style |113| --- | --- |114| Primary entity tables | Solid border. |115| Join tables | Dashed border. |116| Owned types | Lighter stroke or nested inline fields. |117| Technical tables | Muted style. |118| External or migration-only tables | Dotted border. |119120Hide technical tables by default unless requested. Examples include `__EFMigrationsHistory`, Hangfire tables, ASP.NET Identity tables, audit logs, and outbox tables. If hidden, list them in the summary.121122## Procedure1231241. Read the EF Core project structure.1252. Locate all `DbContext` classes.1263. Locate all `DbSet<T>` declarations.1274. Locate entity classes, owned types, enum types, and value objects.1285. Read `OnModelCreating` and all `IEntityTypeConfiguration<T>` classes.1296. Read migrations when available to confirm table names, join tables, indexes, and delete behaviors.1307. Build a normalized database model before writing D2.1318. Ask the mandatory diagram questionnaire before generation.1329. Generate the `.d2` file from the database model, not raw class nesting.13310. Validate D2 syntax with `d2 fmt` before delivery.13411. Render with `d2 --layout=elk schema.d2 schema.svg` when possible.13512. If regenerating, re-read EF Core mappings and migrations first.136137## Progressive disclosure and bundled resources138139Load bundled references on demand:140141- `references/efcore-model-extraction.md`: rules for reading `DbContext`, `DbSet`, Fluent API, configurations, and migrations.142- `references/d2-erd-style.md`: D2 syntax and visual conventions for ERD diagrams.143- `references/relationship-rules.md`: how to infer one-to-one, one-to-many, many-to-many, and owned relationships.144- `references/grouping-modes.md`: rules for `bounded-context`, `schema`, `namespace`, and `flat` grouping.145- `references/quality-gate.md`: final checklist before delivering the generated diagram.146147## Output template148149````markdown150## EF Core D2 diagram — <DbContext or scope>151152**Status:** generated | needs answers | blocked153**Selected DbContext:** <auto-detect/all/name>154**Output format:** d2 | svg | png155**Layout:** elk | dagre | tala156157### D2 source158```d2159<schema.d2 content>160```161162### Render command163```bash164d2 --layout=elk schema.d2 schema.svg165```166167### Assumptions and hidden tables168- Columns: all | key-only | none169- Owned types: inline | separate | hide170- Many-to-many join tables: explicit | compact | hide171- Hidden technical tables: `__EFMigrationsHistory`, <others or none>172173### Validation174- `d2 fmt schema.d2`: pass | fail | not run175- EF Core mappings read: migrations, Fluent API, annotations, conventions176````177178## Quality gate179180- [ ] The selected `DbContext` is clear.181- [ ] All `DbSet<T>` entities are considered.182- [ ] Fluent API configurations in `OnModelCreating` and `IEntityTypeConfiguration<T>` are read.183- [ ] Migrations are checked when present.184- [ ] Table names and schema names match EF Core mapping.185- [ ] Primary keys, foreign keys, cardinalities, optional/required markers, and delete behavior are represented.186- [ ] Owned types follow the user’s `inline`, `separate`, or `hide` choice.187- [ ] Many-to-many join tables are explicit unless the user asked otherwise.188- [ ] Hidden technical tables are listed in the final summary.189- [ ] D2 syntax is valid with `d2 fmt` when the CLI is available.190- [ ] Edge endpoints use full dot-notation when inside containers.191- [ ] The diagram remains readable and avoids crossing-heavy layouts.