Dependency Graph plugin screenshot
Dark mode ready
Multilingual support
Supports v5.x

Dependency Graph

Community

Explore models, Livewire components, resources, panels and relationships from one visual workspace. Filament Dependency Graph automatically discovers the structure of a Laravel and Filament application and presents it through an interactive, navigable interface: a graph, a tree, a table, a contextual inspector, search, focus mode, filtering and exports.

Tags: Analytics Developer Tool
Supported versions:
5.x 4.x
La boîte à code avatar Author: La boîte à code

Package health

Beta

Automated checks of this plugin's Composer package

100 / 100
Security 100
Maintenance 100
Ecosystem 100
15 checks
  • Passed: GitHub Actions pinned to SHA
  • Skipped: GitLab CI includes pinned to SHA
  • Passed: Open security advisories
  • Passed: Dependabot PR responsiveness — No open Dependabot PRs.
  • Skipped: Renovate MR responsiveness
  • Passed: Dependabot or Renovate configured
  • Passed: Dependency update cooldown configured
  • Passed: Provides a security policy
  • Passed: Abandoned or archived — No consulted source marks the package abandoned (packagist, github).
  • Passed: Commit and release recency — Active: last commit 1 days ago; last release 1 days ago.
  • Passed: composer.lock not committed by library composer.lock is absent from the released dist archive.
  • Passed: Dist archive is lean
  • Passed: Current Laravel version supported — Package dependencies resolve together with current Laravel 13.0.
  • Passed: Current PHP version supported — Constraint ^8.3 supports current PHP 8.5.
  • Skipped: Current Symfony version supported
Third-party plugin. This is built by the community, not the Filament team. Filament does not review, endorse, or vet the security of plugins outside the filament/ namespace. Review the source and install at your own risk. Found malware or an unresolved security issue the author won't address? Report it .
Powered by Plumb Last scanned 19 hours ago

Documentation

Latest Version on Packagist Tests Total Downloads License

The visual architecture explorer for Filament.

Explore models, Livewire components, resources, panels and relationships from one visual workspace. Filament Dependency Graph automatically discovers the structure of a Laravel and Filament application and presents it through an interactive, navigable interface: a graph, a tree, a table, a contextual inspector, search, focus mode, filtering and exports.

#The problem

Large Laravel and Filament applications are hard to understand because their structure is scattered across models, relationships, resources, panels, relation managers, policies, traits, casts and morph maps. A developer joining an existing project inspects dozens of files before understanding which models exist, how they connect, which resources expose them and where circular dependencies live. Static diagrams rot; manual documentation is never complete.

#The solution

Install the package, register the plugin, open one page, and immediately answer:

  • Which models exist, and which resources expose them?
  • Which standalone Livewire components use each model?
  • Which panels contain those resources?
  • How are the models connected, and through which relation types?
  • Which models have no resource? Which are isolated?
  • Where do circular dependencies exist?
  • What surrounds this specific model?

#Features

  • Automatic discovery. Eloquent models and relations, application Livewire components, Filament panels, resources, pages and relation managers, with zero package-specific configuration on standard applications.
  • Project-wide Livewire visibility. Components under app/Livewire or the legacy app/Http/Livewire convention appear in the Laravel scope even when they are not registered in a Filament panel. Typed properties, method signatures and explicit static model references become component-to-model dependencies without instantiating the component.
  • Every Eloquent relation type. belongsTo, hasOne, hasMany, belongsToMany, hasOneThrough, hasManyThrough, morphTo, morphOne, morphMany, morphToMany and morphedByMany, including morph maps.
  • A readable graph. Cytoscape.js with a layered dagre layout for the hierarchical mode and fCoSE for the force-directed mode. Relation labels only appear at readable zoom levels, selecting a node fades everything outside its neighborhood, and disconnected models are packed neatly instead of drifting over the graph.
  • Native Filament look. The whole page is built from Filament components (sections, tabs, buttons, selects, checkboxes, badges) and the graph palette reads your panel color scales at runtime, in light and dark mode.
  • Tree and table views for the same data, usable without the graph renderer.
  • Contextual inspector for models, Livewire components, resources, panels and relation edges: keys, pivot tables, morph metadata, traits, casts, rendered views, public APIs and diagnostics.
  • Search across class names, labels, tables, namespaces, panels and relation methods, with deterministic ranking.
  • Focus mode with configurable depth and direction, shareable through the URL query string.
  • Filters. Panels, node types, relation types, namespace, vendor or application ownership, orphans only, circular dependencies only, models without resources only.
  • Deterministic JSON and Mermaid exports, from the UI or the CLI.
  • Snapshot cache with dedicated artisan commands.
  • Full page customization. Navigation label, icon, group, sort, badge, parent item, slug, cluster, max content width and access control - fluently or from the configuration file.
  • Read-only by design. The package never modifies your application or queries business records.
  • Resilient discovery. One broken model or throwing relation method becomes a warning, never a crash.

#Compatibility

The CI matrix is the source of truth.

Package PHP Laravel Filament
1.x 8.3, 8.4, 8.5 12.x, 13.x 4.x, 5.x

#Installation

composer require laboiteacode/filament-dependency-graph

Register the plugin in your panel provider:

use LaBoiteACode\DependencyGraph\DependencyGraphPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            DependencyGraphPlugin::make(),
        ]);
}

That is all: open /admin/dependency-graph in your local environment. The plugin can be registered on several panels, each with its own options.

#Security warning

Class names, table names and relationship metadata are sensitive architecture information. The page is only visible when app()->isLocal() returns true. Never expose it publicly.

To enable it elsewhere, take an explicit decision:

DependencyGraphPlugin::make()
    ->canAccessUsing(fn (): bool => auth()->user()?->can('viewDependencyGraph') === true);

visible() is an alias of canAccessUsing(). The callback replaces the local-only rule entirely, so make it as strict as your context requires.

#The workspace

#Graph view

The default view renders the dependency graph with typed nodes: panels, resource hexagons, Livewire components, model boxes and dashed polymorphic-target diamonds. Two layouts are available from the toolbar:

  • Hierarchical (default) - a layered dagre layout: panels on top, then resources, then models, with crossing minimisation.
  • Force-directed - fCoSE, which clusters tightly related models together and packs disconnected components side by side.

Interactions: zoom and pan, drag nodes, click a node or an edge to open the native Filament inspector slide-over (the rest of the graph fades to keep focus), click the canvas to clear, use the explicit zoom controls or Fit to re-center. The expand control temporarily gives the explorer column back to the canvas; press Esc to restore it. Relation labels appear once the zoom makes them readable.

#Tree view

A cycle-safe, depth-limited expansion of the graph starting from the panels (or from the selected node), with the relation method displayed on every branch. Useful for answering "what hangs off this model" linearly.

#Table view

A native Filament Table exposes four inventory categories - models, relations, Livewire components and resources - through compact tabs. Search, sorting, pagination, column visibility and empty states follow the panel behavior automatically. Counts, aliases, views, foreign keys, pivot tables, navigation groups and discovery status remain available, and every row opens the inspector.

#Inspector

Selecting a node or an edge opens a native Filament slide-over with everything the discovery collected: namespace, table, primary key, soft deletes, traits, casts, relation list with types and keys, pivot metadata, morph maps, Livewire aliases, rendered views and public APIs, panels and pages for resources, plus diagnostics when discovery was partial. Filament handles its focus trap, scroll lock, responsive placement and dismissal consistently with the rest of the panel.

#Focus mode

Press F (or the inspector button) to restrict the graph to the neighborhood of the selected node, with a configurable depth (1, 2, 3 or unlimited) and direction (incoming, outgoing or both). The focus state lives in the URL query string, so the exact view can be shared or bookmarked.

#Search

Press / and type: the search matches class names, labels, table names, namespaces, panel ids and relation methods, grouped by node type. Selecting a result clears the transient filters, selects the node and centers the graph on it.

#Keyboard shortcuts

Key Action
/ Focus search
Esc Close inspector or exit focus mode
F Focus selected node
R Reset graph
G Graph view
T Tree view
L Table view
E Export JSON

#Scopes

  • Filament scope (default): starts from the resources registered in the selected panels and includes their models plus related models up to the configured depth.
  • Laravel scope: every discovered Eloquent model and standalone Livewire component, including models that no resource exposes. Disable it entirely with laravel_scope_enabled => false or ->allowLaravelScope(false).

#Configuration

Publish the configuration file when you need to adjust discovery:

php artisan vendor:publish --tag=filament-dependency-graph-config

Every option, with its default:

use LaBoiteACode\DependencyGraph\Domain\Enums\GraphScope;

return [
    // Master switch: hides the page everywhere, keeps the API and CLI working.
    'enabled' => true,

    // Navigation entry. Every key has a fluent twin on the plugin.
    'navigation' => [
        'label' => null,                  // defaults to the translated label
        'icon' => 'heroicon-o-share',
        'active_icon' => null,
        'group' => null,
        'sort' => null,
        'parent_item' => null,
        'register' => true,               // false keeps the route, hides the menu entry
    ],

    // Page placement and layout.
    'page' => [
        'slug' => 'dependency-graph',
        'cluster' => null,                // a Filament cluster class name
        'max_content_width' => 'full',    // any Filament\Support\Enums\Width value
    ],

    // Scopes.
    'default_scope' => GraphScope::Filament,
    'laravel_scope_enabled' => true,

    // Model discovery.
    'model_paths' => [app_path('Models')],
    'model_namespaces' => ['App\\Models\\'],
    'exclude' => [
        'classes' => [],
        'namespaces' => [],
        'tables' => [],
        'relations' => [],                // "App\Models\Order::customer"
    ],
    'vendor_models' => [
        'enabled' => false,
        'namespaces' => [],
    ],

    // Standalone Livewire components shown in the Laravel scope.
    'livewire' => [
        'enabled' => true,
        'paths' => [
            app_path('Livewire'),
            app_path('Http/Livewire'),
        ],
        'namespaces' => [
            'App\\Livewire\\',
            'App\\Http\\Livewire\\',
        ],
    ],

    // Discovery behavior.
    'discovery' => [
        'relations' => true,
        'database_schema' => true,
        'docblocks' => true,
        // Calls untyped methods to check whether they return a relation.
        // Disabled by default: invoking arbitrary methods may trigger
        // application side effects.
        'heuristic_relation_invocation' => false,
    ],

    // Graph defaults.
    'graph' => [
        'default_depth' => 2,
        'default_direction' => 'both',
        'default_layout' => 'hierarchical',
        'show_panel_nodes' => true,
        'show_resource_nodes' => true,
        'show_orphans' => true,
    ],

    // Snapshot cache (bypassed automatically in the testing environment).
    'cache' => [
        'enabled' => true,
        'store' => null,
        'ttl' => 3600,
    ],

    // The page is local-only unless a visibility callback says otherwise.
    'authorization' => [
        'local_only' => true,
    ],

    // Built-in exporters.
    'exports' => [
        'json' => true,
        'mermaid' => true,
    ],
];

The plugin exposes the discovery knobs fluently:

DependencyGraphPlugin::make()
    ->defaultScope(GraphScope::Filament)
    ->defaultDepth(2)
    ->allowLaravelScope()
    ->scanVendorModels(false)
    ->scanLivewireComponents()
    ->excludeModels([AuditLog::class])
    ->registerModelPath(app_path('Domain'))
    ->registerModelNamespace('App\\Domain\\')
    ->registerLivewirePath(app_path('Domain/Livewire'))
    ->registerLivewireNamespace('App\\Domain\\Livewire\\')
    ->registerExporter(new MyGraphvizExporter())
    ->registerInspector(new MyAuditableInspector());

#Customizing the page

Navigation, page placement and layout follow the same conventions as the other La Boite a Code plugins. Everything is available fluently on the plugin, or under the navigation and page keys of the configuration file; the plugin wins when both are set:

use Filament\Support\Enums\Width;

DependencyGraphPlugin::make()
    ->navigationLabel('Architecture')
    ->navigationIcon('heroicon-o-share')
    ->activeNavigationIcon('heroicon-s-share')
    ->navigationGroup('Developer tools')      // string, enum or closure
    ->navigationSort(30)
    ->navigationParentItem('Tooling')
    ->navigationBadge(fn (): string => 'beta')
    ->registerNavigation(false)               // keep the route, hide the menu entry
    ->slug('architecture-map')
    ->cluster(\App\Filament\Clusters\Developer::class)
    ->maxContentWidth(Width::SevenExtraLarge)
    ->canAccessUsing(fn (): bool => auth()->user()?->isDeveloper() ?? false);

The page renders full width by default so large graphs get the whole viewport; set page.max_content_width (or maxContentWidth()) to any Filament\Support\Enums\Width value to constrain it.

#Translations

Every label ships in English and French. Publish the language files to adjust or add locales:

php artisan vendor:publish --tag=filament-dependency-graph-translations

#Views

The Blade views are publishable for deep customization, although the stable extension points (exporters, inspectors, configuration) should cover most needs:

php artisan vendor:publish --tag=filament-dependency-graph-views

#Theming

The interface is built from the native Filament Blade components (sections, tabs, buttons, selects, checkboxes, badges) and the graph palette reads your panel color scales (primary, success, info, warning, gray) at runtime, so a custom Filament theme restyles the whole page - including the graph - without any extra work.

#Exports

From the UI: the toolbar downloads the current graph, filters included, as JSON or Mermaid.

From the CLI:

php artisan filament-dependency-graph:export
    {--format=json : Export format, json or mermaid}
    {--scope= : Graph scope, filament or laravel}
    {--panel=* : Only include the given panel ids}
    {--focus= : Focus on a node id, for example model:app.models.order}
    {--depth= : Focus traversal depth}
    {--direction=both : Focus direction, incoming, outgoing or both}
    {--output= : Write the export to this file instead of standard output}
    {--force : Overwrite the output file when it exists}

For example:

php artisan filament-dependency-graph:export \
    --format=mermaid \
    --scope=laravel \
    --output=docs/dependency-graph.mmd

Both exports are deterministic: same application state, same output. Diff them in CI to detect architecture drift, or commit the Mermaid file next to your documentation.

#Cache

Discovery relies on reflection and file scanning, so snapshots are cached. The cache stores the discovered snapshot only - never rendered output - and is bypassed automatically in the testing environment.

# Warm the cache, for example in a deploy pipeline
php artisan filament-dependency-graph:cache
    {--scope= : Discovery scope, filament or laravel}
    {--panel=* : Only discover the given panel ids}
    {--no-schema : Skip database schema inspection}
    {--force : Rebuild even when a cached snapshot exists}

# Clear every cached snapshot
php artisan filament-dependency-graph:clear

The cache key includes the package schema version, the runtime versions and every discovery setting, so configuration changes never serve stale graphs.

#Programmatic API

The facade proxies the DependencyGraphManager contract, so everything the UI does is scriptable:

use LaBoiteACode\DependencyGraph\Domain\Enums\GraphScope;
use LaBoiteACode\DependencyGraph\Domain\ValueObjects\GraphQuery;
use LaBoiteACode\DependencyGraph\Facades\DependencyGraph;

// Raw discovery snapshot: models, relations, Livewire components, panels,
// resources and warnings.
$snapshot = DependencyGraph::discover();

// Full graph with the default query.
$graph = DependencyGraph::graph();

// Focused sub-graph.
$graph = DependencyGraph::graph(new GraphQuery(
    scope: GraphScope::Laravel,
    panelIds: ['admin'],
    focusNodeId: 'model:app.models.order',
    depth: 2,
));

$graph->nodeCount();
$graph->edgeCount();
$graph->toArray();

// Exports.
$json = DependencyGraph::export('json');
$mermaid = DependencyGraph::export('mermaid');

DependencyGraph::clearCache();

GraphQuery accepts the scope, panel ids, node types, relation types, a focus node with depth and direction, and whether orphans are included - the same capabilities as the UI filters.

#Extending

#Custom exporters

Implement the GraphExporter contract and register it on the plugin:

use LaBoiteACode\DependencyGraph\Contracts\GraphExporter;
use LaBoiteACode\DependencyGraph\Domain\Graph\Graph;
use LaBoiteACode\DependencyGraph\Domain\ValueObjects\ExportOptions;

class GraphvizExporter implements GraphExporter
{
    public function format(): string
    {
        return 'dot';
    }

    public function export(Graph $graph, ExportOptions $options): string
    {
        // Walk $graph->nodes and $graph->edges, return DOT markup.
    }
}

DependencyGraphPlugin::make()
    ->registerExporter(new GraphvizExporter());

The format becomes available in the UI and through the facade on panel requests. For console usage (--format=dot), register the exporter in a service provider instead, by resolving LaBoiteACode\DependencyGraph\Export\ExportManager and calling register() - the plugin only boots with its panel.

#Custom inspectors

Implement the NodeInspector contract to enrich (or replace) the inspector panel for the nodes you care about. Custom inspectors are consulted before the built-in ones:

use LaBoiteACode\DependencyGraph\Contracts\NodeInspector;

DependencyGraphPlugin::make()
    ->registerInspector(new MyAuditableInspector());

#Troubleshooting

  • The page returns 404 outside your machine. Expected: the page is local-only by default. Configure canAccessUsing() deliberately (see the security warning).
  • The graph looks unstyled or outdated after an update. Republish the Filament assets: php artisan filament:assets.
  • Some models are missing. Discovery scans model_paths and model_namespaces; add your custom locations there or with registerModelPath() / registerModelNamespace(). Vendor models are excluded unless vendor_models.enabled is true.
  • A Livewire component is missing. Add its source directory and namespace under livewire.paths / livewire.namespaces, or use registerLivewirePath() / registerLivewireNamespace(). Components are visible in the Laravel scope, not the Filament scope.
  • A Livewire-to-model link is missing. The read-only scanner recognizes model types on component properties and methods, plus explicit static references such as Order::query(). Dynamic container resolution and untyped variables cannot be inferred safely.
  • A relation is not detected. Untyped relation methods are only discovered through docblocks (enabled by default) or heuristic invocation (disabled by default, because it calls the methods). Add a return type to the relation method for the most reliable detection.
  • A model shows a warning badge. Discovery is resilient: the inspector's diagnostics section lists exactly what failed for that class.

#Testing

composer test
composer analyse
composer lint

The suite runs on Pest with Orchestra Testbench against a realistic fixture domain covering every supported relation type, multi-panel resources and failure scenarios.

#Architecture

The codebase is layered: a framework-agnostic domain (graph model, DTOs, algorithms), an application layer (use cases), infrastructure (discovery, cache, exporters) and a Filament presentation layer. Filament 4 and 5 differences are isolated behind a compatibility adapter. Architecture decision records live in docs/adr.

#Changelog

See CHANGELOG.md for release notes.

#Contributing

See CONTRIBUTING.md. Please report security issues privately as described in SECURITY.md.

#Credits

#License

Open source under the MIT license.

The author

La boîte à code avatar Author: La boîte à code

La Boîte à Code is a French web studio based in Perpignan, founded and led by Alexandre Ribes. We design and build custom web applications, business software and SaaS products on the Laravel and TALL stack (Tailwind, Alpine, Laravel, Livewire), with Filament for the back-office side.

Our model is simple: one project at a time, clear ownership, high technical standards. We structure it, we build it, we ship it. No detours, and nothing that falls apart six months later.

We don't promise everything. We ship what matters.

Plugins
5
Stars
9

From the same author