tyro-dashboard: a Laravel admin panel configured instead of coded
Powerful and feature-rich dashboard for Laravel 13 and 12. Comes with complete authentication, user management, roles and privilege management, media management and dynamic CRUD
At a glance
- What is it?
- tyro-dashboard gives a Laravel 12 or 13 application an admin panel with user management, RBAC, separate admin and user dashboards, audit trails, a media library and dynamic CRUD, where a resource is described in a config array and the package generates the controllers, views, routes and validation. It sits on two sibling packages, Tyro for roles and Tyro Login for authentication.
- Who is it for?
- tyro-dashboard suits a team that keeps rebuilding the same admin screens and wants a resource to be a config array rather than a controller, a view and a form request, and the audit trail and impersonation features are the parts that are hard to retrofit onto an existing panel. It does not suit you if you need unusual interfaces, since the generated CRUD follows a fixed pattern and the escape hatch is writing your own pages rather than configuring them.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Blade, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three packages, and what each one owns
tyro-dashboard is a comprehensive admin panel package for Laravel 12 and 13, and it does not stand alone. It is built on top of Tyro, which is the RBAC package, and Tyro Login, which is the authentication package. Both are by the same author, and all three are listed as requirements alongside PHP 8.2 or newer and Laravel 12 or 13.
That split is worth understanding before you install anything, because it tells you what you are actually adopting. Authentication, including the two-factor and passkey support, lives in Tyro Login. Roles and privileges live in Tyro. The dashboard is the layer that turns a model into a set of screens.
What you get is user management with full CRUD, search, suspension, 2FA, passkeys and role assignment, and RBAC with visual role and privilege management with protected roles. There is impersonation, which lets an administrator log in as any user to troubleshoot and verify features, which is a feature that is easy to add and hard to retrofit later. There are separate dashboards, so the admin and user experiences are distinct out of the box rather than one interface with hidden buttons. There is an audit trail with searchable logs of all admin activities and resource changes, an admin bar for global maintenance and announcement notices, an invitation system with referral links and automatic signup tracking, and profile photos with custom uploads or a Gravatar fallback.
The media library is the other substantial piece, with media management, uploads, WebP conversion, thumbnails, stock photo search and a reusable media picker. The emailer is a rich-text mail composer with switchable preset templates for Modern, Corporate, Newsletter and Plain, live preview and background queue dispatching. And there is a system health page, which is read-only runtime diagnostics covering PHP memory, OPcache, disk, database, cache and queue status.
The README frames the whole thing as a time saving claim: what would take 40 to 60 hours of development now takes minutes of configuration.
Dynamic CRUD, where a resource is an array rather than a controller
The feature that distinguishes this package from a starter kit is that the CRUD is generated from configuration.
You add a trait to your model:
use HasinHayder\TyroDashboard\Concerns\HasCrud;
class Product extends Model
{
use HasCrud;
}and then describe the resource in the package configuration file:
'resources' => [
'products' => [
'model' => App\Models\Product::class,
'roles' => ['admin', 'manager'],
'fields' => [
'name' => ['type' => 'text', 'required' => true, 'searchable' => true],
'price' => ['type' => 'number', 'required' => true, 'sortable' => true],
'category_id' => ['type' => 'select', 'relationship' => 'category'],
'image' => ['type' => 'file'],
'is_active' => ['type' => 'checkbox', 'default' => true],
],
],
]Visiting the resource route then gives you a live admin interface with list views, pagination, search, sortable columns, create and edit forms with validation, file uploads, relationships and role-based access. The README summarises what you avoid: no controllers, no views, no routes, no validation logic, just configuration.
The field types are what make it more than a table view. A text field marked required and searchable, a number field that is sortable, a select field with a relationship to another model, a file field for uploads, and a checkbox with a default value. The roles key on the resource is the access control, so the same generated screens are visible to the roles you list and not to the others.
The gap between the trait and the config array is the actual API surface, and it is deliberately narrow. Anything more elaborate than those field types is where you would stop using the generator, which is why the package also ships commands for creating your own dashboard pages.
The parts that are hard to retrofit, and the parts that are ordinary
A dashboard package is easy to oversell, so it is worth separating what this one genuinely removes from your workload and what it merely moves.
The genuinely hard parts are the three you would otherwise write and then maintain. Authentication with two-factor and passkeys is a security feature, and a home-grown version of it is a liability. Role and privilege administration with protected roles is a UI and a data model problem that every project ends up solving badly, because the rules are always more complicated than the first version assumes. And the audit trail of admin activities and resource changes is the part that a compliance conversation in month eight turns into a quarter of work, because an audit log retrofitted afterwards does not record the history you needed.
Impersonation belongs in that group too. Logging in as a user to reproduce a bug is trivial to add at the start and surprisingly hard later, because it has to be audited, because it has to be limited, and because the sessions of the impersonated user interact with every other part of the system.
The ordinary part is the CRUD, and that is the part the config array covers. If your model has a name, a price, a category, an image and a flag, you have written that screen before and you will write it again. Generating it is worth doing.
The rest of the feature list is a mixture. The media library with WebP conversion, thumbnails and a reusable picker is real work that most projects defer. The emailer with preset templates and background dispatch is work that most projects write badly. The system health page is a read-only diagnostic view that is genuinely useful and genuinely boring to build. The admin bar for maintenance and announcement notices is a small feature that people appreciate more than they expect. And the invitation system with referral tracking is the kind of thing that only matters for a product with a growth model.
So the honest summary is that this package front-loads the work you would postpone and get wrong, and the dynamic CRUD covers the work you would just have to repeat. That is a good trade for most admin panels, and it is a bad fit for a product whose admin interface is the product.
The command surface, and the split between publishing and creating
The package exposes a large set of artisan commands, and the grouping tells you how the package is meant to be used.
Installation is two commands:
composer require hasinhayder/tyro-dashboard
php artisan tyro-dashboard:installThe install command publishes the config, views, routes and middleware for you, and then you visit the dashboard route in your browser. The README says this gets you up and running in under three minutes.
The rest of the commands fall into three groups. The first is publishing and updating, which is about keeping what the package ships in step with what you have published: publish for views, config and styles with per-area options, publish-style to publish the styles used to customise the shadcn variables, update for published resources and sidebar overrides, and separate update commands for the config, the styles and the scripts. There is also setup-ai-skill, which installs a Tyro Dashboard AI skill for your agent.
The second group is about pages and resources. There are create commands for an admin page, a user page and a common page visible in both sidebars, matching remove commands, and make-resource to scaffold a new resource with its model, migration and controller. The make-resource command is the important one, because it is the escape hatch: it generates the conventional Laravel files for a resource you then own, rather than a config entry the package controls.
The third group is smaller: clear-cache for cached field configurations in the dynamic CRUD, createsuperuser to create a superuser with admin privileges, and version to print the current version. Running php artisan list tyro-dashboard shows everything.
The caching of field configurations is worth noting, because it explains a class of confusing behaviour. If you change a resource's fields and nothing appears to change, the cached configuration is the reason, and clear-cache is the fix.
Blade components, and the licence and version picture
The package ships a library of shadcn-styled Blade components that you can drop into any page immediately, with no build step required. They are used through the tyro-dashboard namespace, so a card element is written as a component tag with the package namespace.
That no build step wording matters for how the components are delivered. The components are Blade components rather than a bundled JavaScript library, so they arrive as part of the package and the styling comes from the published styles you can adjust, with publish-style and the shadcn variables as the customisation point. The UI is described as modern and responsive, with shadcn components and dark and light themes, and the components cover the usual set, starting with an alert that takes a variant of info, success, warning or error, and an avatar with a photo or Gravatar fallback to initials.
The security framing in the feature list is worth reading carefully rather than skipping. Security first means middleware checks, per-resource access and protected resources, and the RBAC page is visual with protected roles, which implies some roles cannot be edited through the interface.
On packaging, the badges give the version matrix: Laravel 12.x and 13.x, PHP 8.2 and newer, MIT licensed, and a CLI Ready badge pointing at the command surface. The package is on Packagist as hasinhayder/tyro-dashboard, and the documentation is hosted at hasinhayder.github.io/tyro-dashboard with a separate doc page. The primary language is recorded as Blade, which is a reflection of where the work is, since the package is largely templates and configuration rather than application logic.
The repository layout is a Laravel package with the usual directories, config/, database/, resources/, routes/, src/ and tests/, plus a skills/ directory, a pint.json for code style, a CHANGELOG.md and an AGENTS.md. The last push was on 2026-10-17 and there are no GitHub releases, so the Packagist version is the version to track.
Editorial conclusion
tyro-dashboard suits a team that keeps rebuilding the same admin screens and wants a resource to be a config array rather than a controller, a view and a form request, and the audit trail and impersonation features are the parts that are hard to retrofit onto an existing panel. It does not suit you if you need unusual interfaces, since the generated CRUD follows a fixed pattern and the escape hatch is writing your own pages rather than configuring them. Before you install it, note that it needs three packages, not one, and that the invitation system arrived in a later version, so an upgrade needs a migration for the invitation_links and invitation_referrals tables.
Frequently asked questions
How do I install tyro-dashboard?
Run composer require hasinhayder/tyro-dashboard and then php artisan tyro-dashboard:install, which publishes the config, views, routes and middleware. You then visit /dashboard in your browser. PHP 8.2 or newer, Laravel 12 or 13, and the Tyro and Tyro Login packages are also required.
How does dynamic CRUD work in tyro-dashboard?
You add the HasCrud trait to your model and describe the resource in config/tyro-dashboard.php, listing the model, the roles allowed to see it and the fields with their types, whether they are required, searchable or sortable. The package then generates the list view, pagination, search, sortable columns, forms with validation, file uploads and relationship fields, with no controllers, views, routes or validation logic of your own.
What does the tyro-dashboard install command actually do?
tyro-dashboard:install publishes the package resources, namely the config, views, routes and middleware. There are separate commands for publishing and updating each of those areas, and clear-cache for the cached field configurations used by the dynamic CRUD, which is the reason to reach for it when a field change does not appear.
Is there anything to do when upgrading tyro-dashboard to a version with the invitation system?
Yes. The README notes that if you are updating to a version with the invitation system, you need to run php artisan migrate to create the invitation_links and invitation_referrals tables.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/hasinhayder-tyro-dashboard)