Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Truss Laravel Package

albertoarena/laravel-truss

Laravel Truss scans your live database schema and renders it as a scrollable, zoomable ER diagram inside your app. Structure only, never row data. Focus mode, searchable tables, themes, and export.

View on GitHub
Deep Wiki
Context7

Getting Started

Truss is a dev-time observability tool for your schema, not a runtime dependency. The whole setup is:

composer require albertoarena/laravel-truss --dev
php artisan serve
# open http://localhost:8000/truss

The service provider auto-discovers, there is nothing to publish, and the default config is already useful: enabled in local only, reading your default connection, rendering structure only. If you are on Laravel 12+ and PHP 8.2+ you are done in under a minute.

Where to look first. Don't start by panning around the whole diagram — on any real app it's a wall of boxes. Use focus mode: pick your users, orders, or whatever the team argues about most, and read its foreign-key neighbourhood with native types off (Laravel-style labels on). That single view is usually the fastest way to answer "what actually references this table and with what nullability."

First use case worth institutionalising. Point it at your ugliest legacy database and export a Markdown data dictionary:

php artisan truss:export --format=markdown --output=docs/schema.md

Ten seconds later you have a committable artifact that new hires and coding agents can read. That is the moment the package stops being a novelty and becomes part of the workflow.

Implementation Patterns

Onboarding and schema archaeology. Treat /truss as the shared whiteboard during pairing sessions. Focus mode is searchable on any substring of the table name, which is what keeps it usable on 200+ table schemas where a full ER diagram is unreadable. Export to PNG/SVG when you need to paste something into a PR description, Slack, or an architecture doc.

Documentation that can't rot. Commit a DBML file and enforce it in CI:

php artisan truss:export --format=dbml --output=docs/schema.dbml --check

--check writes nothing, compares bytes, and exits 1 on drift. Because the output is deterministic (stable table ordering regardless of what the database reports), this is a reliable drift gate rather than a flaky one. Run it on the same job as your test suite so a migration that changes structure without refreshing the committed file fails the build.

Migration hygiene as a build gate. Wire the schema doctor into CI alongside it:

php artisan truss:doctor --preset=recommended --fail-on=warning

Start with the default --fail-on=error, then tighten to warning once you've cleared the backlog. Findings carry stable codes (TRUSS-IDX-001), so you can suppress individual rules or tables via truss.doctor config rather than disabling the whole check. The same findings show in the dashboard's Health panel, and each problem table gets a severity badge on the diagram, so the terminal and the UI never disagree.

Feeding coding agents real structure. This is the highest-leverage pattern if your team uses Claude Code or Cursor. The llm format plus trimming flags gives an agent grounding that a hand-written description never keeps accurate:

php artisan truss:export --format=llm --compact --focus=orders --depth=1

Pair it with annotations in config/truss.php to encode the things types can't express — that status = 1 means paid, that a table is deprecated — or set annotations.source to include 'database' to pull native column comments. For agents that speak MCP, the bundled read-only server is strictly better than pasting: the agent queries the current schema on demand instead of working from a stale snapshot.

Programmatic access instead of shelling out. When you need this in a test, an artisan command, or a docs generator, use the facade — it produces byte-identical output to the CLI:

use AlbertoArena\Truss\Facades\Truss;

$llm = Truss::snapshot()
    ->connection('modules')
    ->only(['orders', 'order_lines'])
    ->focus('orders', depth: 1)
    ->compact()
    ->withoutAnnotations()
    ->toLlm();

The builder is immutable, so a base builder defined once can be shared and narrowed per call site without surprise mutation.

Multi-connection apps. For a main DB plus a module DB, list both under truss.connections. Each connection is introspected against its own database only, so shared servers won't bleed another app's tables into your diagram, and per-connection excluded_tables lets you hide different tables per database. The selected connection is kept in the URL, which makes diagram links shareable in tickets.

Reviewing schema changes in a PR. php artisan truss:diff (and the dashboard Changes panel) gives you added/removed/changed tables, columns, indexes, and foreign keys. Use it to sanity-check a migration branch before merge — especially for index drops and column type changes that a reviewer would otherwise miss in the diff of the migration file itself.

Gotchas and Tips

--dev means production 404s, by design. If you want Truss reachable on staging, install it as a regular dependency — composer install --no-dev strips dev packages, so --dev installs never ship. Combine that with the non-local requirements: you must both enable it and authorise viewers behind the viewTruss gate. Don't hand-wave that gate. A schema is not row data, but table names, column names, and relationships leak a lot of business logic, and an unauthenticated /truss on a public staging host is a real finding.

excluded_tables always wins over --tables. This is intentional (the export can never expose a table the dashboard hides) but it surprises people: passing --tables=telemetry_events to an export yields nothing if that table is excluded in config, and with no tables matched you get exit code 2, not an empty file. Check config exclusions before debugging your flag syntax.

Know what refreshes the snapshot. The cached snapshot rebuilds automatically after migrations — that's the common path. It does not know about raw SQL run by hand, a restored dump, or a table created outside the migration system, so the diagram and every export can silently lag reality. --fresh forces a rebuild on export; when a diff or doctor result looks wrong, that's the first thing to try.

Distinguish exit code 1 from 2 in CI. 1 is a meaningful signal (drift found, or a doctor finding at/above --fail-on). 2 is a broken invocation or snapshot error — unknown format, unwritable path, --check without --output, unmanaged connection. Collapsing both into "build failed, look at logs" wastes time; branch on them or at least echo the code in the job output.

Annotations change export bytes. If you edit annotations in config, your committed DBML will drift and --check will fail — correctly, but it's worth knowing before you assume a migration caused it. Use --no-annotations for the committed file if you want the drift gate to track structure only.

Tune the doctor, don't mute it. Some rules are heuristic and flagged as lower-confidence in the output. Start with recommended, fix what's genuinely yours, and use per-rule severity and ignore patterns for the rest — legacy tables with no primary key that you genuinely cannot change should be narrowed out by pattern, not by flipping the whole check off. Turning off doctor.dashboard (TRUSS_DOCTOR_DASHBOARD=false) only silences the panel; the CLI is unaffected, so CI keeps working.

Custom themes can undo the accessibility work. The package ships vendored Mermaid and fonts (offline-safe, CSP-safe, no build step) and is axe-core checked on every push — but a custom palette from the theme builder can break contrast and focus visibility. If you override colours, run your own accessibility pass; the defaults are the only configuration anyone has actually audited for you.

Mind the route prefix. The dashboard and the gated GET {prefix}/export/{format} route both live under a configurable prefix. If your app owns /truss, change it in config rather than fighting the router — and remember the export route accepts only, except, focus, depth, compact, and connection as query parameters, so it's an easy way to generate documentation links straight from a Blade view.

Prefer the facade over exec() in tests. CLI, facade, and dashboard all share one pipeline and produce the same bytes for the same filters. Asserting against Truss::snapshot()->toArray() in a test is faster and clearer than shelling out to truss:export and parsing stdout.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo