byrcsc / laravel-cartographer
Generate a Mermaid entity relationship diagram of your Laravel application from its Eloquent models and database schema.
Fund package maintenance!
Requires
- php: ^8.2
- illuminate/console: ^11.0 || ^12.0
- illuminate/database: ^11.0 || ^12.0
- illuminate/filesystem: ^11.0 || ^12.0
- illuminate/support: ^11.0 || ^12.0
Requires (Dev)
- larastan/larastan: ^2.9 || ^3.0
- laravel/pint: ^1.17
- orchestra/testbench: ^9.5 || ^10.0
- pestphp/pest: ^3.0 || ^4.0
- pestphp/pest-plugin-laravel: ^3.0 || ^4.0
- phpstan/phpstan: ^1.11 || ^2.0
This package is auto-updated.
Last update: 2026-08-05 06:31:17 UTC
README
Generate a Mermaid entity relationship diagram of your Laravel application from its Eloquent models and database schema. Every app eventually needs one: onboarding a developer, planning a migration, working out what still points at a table. Drawn by hand, it is wrong within a month.
The package provides the diagram generator. Your application keeps ownership of its models, its schema, and where the output file lives. Cartographer never reads your data.
| Laravel | Tested PHP versions |
|---|---|
| 12.x | 8.3, 8.4 |
| 13.x | 8.3, 8.4 |
Tested on MySQL, PostgreSQL, and SQLite.
One artisan command writes a Markdown file that GitHub and GitLab render on sight. Commit it, and each schema change shows up as a diff in the pull request that caused it.
php artisan cartographer:erd
erDiagram
categories }o--|| categories : "parent"
categories ||--o{ categories : "children"
categories ||--o{ posts : "posts"
comments }o--|| posts : "commentable (morph)"
comments }o--|| users : "author"
comments }o--|| users : "commentable (morph)"
documents }o--|| users : "owner"
posts }o--|| categories : "category"
posts ||--o{ comments : "commentable (morph)"
posts ||--o| comments : "commentable (morph)"
posts }o--o{ tags : "tags"
posts }o--o{ tags : "taggable (morph)"
posts }o--|| users : "author"
tags }o--o{ posts : "posts"
tags }o--o{ posts : "taggable (morph)"
telemetry_events }o--|| users : "alternateUser"
telemetry_events }o--|| users : "untypedUser"
telemetry_events }o--|| users : "user"
users ||--o{ comments : "postComments (through)"
users ||--o| comments : "firstPostComment (through)"
users ||--o{ comments : "commentable (morph)"
users ||--o{ documents : "documents"
users ||--o| documents : "primaryDocument"
users ||--o{ posts : "posts"
categories {
bigint id PK
bigint parent_id FK
}
comments {
bigint author_id FK
bigint id PK
}
documents {
varchar id PK
bigint owner_id FK
}
post_tag {
bigint id PK
bigint post_id FK, UK
bigint tag_id FK, UK
}
posts {
bigint author_id FK
bigint category_id FK
bigint id PK
}
taggables {
bigint tag_id FK, UK
bigint taggable_id UK
varchar taggable_type UK
}
tags {
bigint id PK
varchar name UK
}
telemetry_events {
bigint id PK
bigint user_id FK
}
users {
varchar email UK
bigint id PK
}
Loading
Installation
Install as a dev dependency:
composer require --dev byrcsc/laravel-cartographer
Publish the config file if you want to change the defaults:
php artisan vendor:publish --tag=cartographer-config
How it works
Cartographer never reads your data. It builds the diagram from two sources:
- Your models. Relationship methods are resolved through Eloquent itself,
so foreign keys, pivot tables, and polymorphic names come out exactly as
your application resolves them. This covers
belongsTo,hasOne,hasMany,belongsToMany, everymorph*relation, and thethroughrelations. - Your schema. Tables, columns, types, and keys come from Laravel's native schema introspection on your development connection. Structure only: no query ever touches your rows.
Because the schema is read from the database, it stays correct on apps with squashed migrations, raw SQL migrations, and long migration histories.
Quick start
Generate the full ERD to docs/erd.md:
php artisan cartographer:erd
Everything is included by default. Use the options to limit it:
| Option | Default | Purpose |
|---|---|---|
--models=Order,Invoice |
all models | Seed models to focus on |
--depth=2 |
unlimited | How many relationship hops to follow from the seeds |
--columns=all|keys|none |
all |
Column detail per entity. keys shows only PK, FK, and unique columns |
--exclude-relations=through,morph |
none | Relation types to leave out |
--format=markdown|mmd |
markdown |
Markdown with a mermaid fence, or a raw .mmd file |
--output=docs/erd.md |
from config | Where the file is written |
--stdout |
off | Print to stdout instead of writing a file |
--connection= |
default connection | Which database connection to introspect |
Output is deterministic: tables, columns, and edges are always emitted in the same order, so the committed ERD only changes when your schema or models do.
Configuration
return [ // Directories scanned for models. Globs are supported, // so modular layouts work: 'src/Domain/*/Models'. 'paths' => [ app_path('Models'), ], // Model classes to leave out of every diagram. 'exclude_models' => [], // Connection to introspect. Null uses your default connection. 'connection' => null, // Output location, relative to the project root. 'output' => 'docs/erd.md', // Renderer format: markdown | mmd. 'format' => 'markdown', 'columns' => [ // Column detail per entity: all | keys | none. 'mode' => 'all', // Columns to hide, keyed by model class. 'exclude' => [], ], 'relations' => [ // Relation types to leave out: 'through', 'morph', ... 'exclude' => [], // Only inspect methods with a declared Relation return type. 'strict_types_only' => false, ], ];
The published config/cartographer.php documents every key inline. Defaults
and validation rules are in the configuration reference under Documentation
below.
A note on how relations are found
Cartographer instantiates each model and invokes its public zero-argument
methods inside a guard, keeping only the ones that return a Relation.
Building a relation object does not run a query. If your models have
zero-argument methods with side effects, either exclude those models or turn
on strict_types_only and type your relation methods.
Documentation
- Introduction
- Installation and setup
- Quick start
- How a diagram is built
- Model discovery
- Relationship detection
- Schema introspection
- Scoping a diagram
- Diagrams per subsystem
- Keeping the diagram current
- Continuous integration
- Configuration
- Console commands
- Diagram syntax
- PHP API
- Testing
- Troubleshooting
Out of scope
Things this package will not do, so you can decide quickly whether it fits:
- Parse migration files. Migrations are history, not a schema. The database structure is the single source of truth.
- Read table data. No query ever runs against your rows. Introspection reads structure only.
- Support Laravel 11 or older. Laravel 11 no longer receives security patches. Laravel 10 and older also need doctrine/dbal for introspection, which is a permanent second code path for end-of-life framework versions.
- Support ORMs other than Eloquent.
- Add routes, pages, or anything browser-facing to your app. Cartographer is an artisan command that writes files.
Rendering Mermaid to PNG or SVG is not in the package today. GitHub, GitLab,
and mmdc already render the output; a built-in exporter may be considered
later if there is real demand.
Versioning
The package follows semantic versioning.
- Upgrading within
1.xis safe. Nothing you use will break. - Only a new major version, like
2.0.0, can break your code. - If the README or the documentation describes it, it is safe to build on. If they don't, treat it as internal and expect it to change.
Concretely, that covers the cartographer:erd command and its options, the
config file keys and their defaults, and the classes on the PHP API reference
page.
One deliberate exception: the exact layout of the generated diagram is not covered. Cardinality notation, edge labels, and column ordering may be refined in a minor release, which will show up as a diff in your committed ERD the next time you regenerate it. Determinism is guaranteed, so a given schema always produces the same file on a given version, but the rendering itself is free to improve. Anything that moves lines gets a changelog entry.
Bug fixes go into the newest version only. To get a fix, upgrade to it.
Questions and issues
- Stuck, or have an idea? Start a discussion. Usage questions and feature ideas both live there.
- Found a bug you can reproduce? Open an issue. A failing test is the fastest way to a fix, and a short reproduction is the next best thing.
- Found a security problem? Please don't open a public issue. See SECURITY.md for how to report it privately.
- Planning a pull request? CONTRIBUTING.md covers the setup and the three checks it needs to pass.
This package is maintained by one person, so replies can take a while. Everything gets read.
License
MIT. See LICENSE.md. Changelog in CHANGELOG.md.