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 Admin Laravel Package

dcat/laravel-admin

dcat/laravel-admin is a fast, elegant admin panel for Laravel. Build CRUD interfaces with rich grids, forms, filters, and widgets in minutes. Includes authentication, permissions, menus, and customizable UI components, making backend development simple and productive.

View on GitHub
Deep Wiki
Context7

Getting Started

Dcat Admin is a Laravel package (not a standalone app) that registers its own service provider, auth guard, routes, and asset pipeline under a configurable prefix (default /admin). Think of it as a model-driven CRUD framework: you write Grid, Form, and Show builders in a controller, and the package renders a full Bootstrap 4 admin UI around them.

Note on release state: the current line is still the 2.2.x-beta track (latest: 2.2.3-beta). There is no stable 2.x tagged release, and no official Laravel 11/12 support. Treat composer require dcat/laravel-admin as pulling a beta — pin the exact version in composer.json.

Install (2.x, Laravel 8–10):

composer require dcat/laravel-admin
php artisan admin:publish      # publishes config/admin.php, migrations, assets, app/Admin skeleton
php artisan admin:install      # runs migrations, seeds admin user, creates app/Admin

Then log in at /admin with admin / admin and change that immediately.

Where to look first, in order:

  1. config/admin.php — route prefix, auth.guard, DB connection, upload disk, directory (the app/Admin path).
  2. app/Admin/routes.php — every admin page is a normal Laravel route registered here; nothing is auto-discovered.
  3. app/Admin/bootstrap.php — global extension points (Grid::resolving(), Form::resolving(), Admin::css(), Admin::jsVariable(), menu/asset tweaks).
  4. The generated app/Admin/Controllers/* — the scaffolding is the best documentation the project has.

First use case — a working CRUD in three commands:

php artisan admin:make UserController --model=App\\Models\\User

Add to app/Admin/routes.php:

$router->resource('users', UserController::class);

Reload /admin, then open Auth → Menu and add a menu item pointing at users. You now have list/create/edit/delete, a filter panel, pagination, and a detail page — with roughly zero HTML. From there, edit the generated grid() and form() methods; that loop (scaffold → refine builder → add menu) is 80% of day-to-day work.

Implementation Patterns

Treat scaffolding as a draft, not the deliverable. admin:make produces generic builders with every column exposed. Immediately prune columns, add ->sortable(), add a $grid->filter(), and tighten the form with ->required()/->rules(). Reviewers will otherwise see password hashes and internal IDs in the list view. (2.2.3-beta also fixes the scaffolded primary key — if you generate against non-incrementing / UUID keys on an older beta, expect to hand-correct $grid->model()->getKeyName().)

Grid: query shaping belongs on the model.

protected function grid()
{
    return Grid::make(new User(), function (Grid $grid) {
        $grid->model()->with(['roles', 'profile'])->where('is_banned', 0);

        $grid->column('id')->sortable();
        $grid->column('name')->display(fn ($v) => Str::limit($v, 20));
        $grid->column('status')->using([0 => 'Off', 1 => 'On'])->label();
        $grid->column('created_at')->sortable();

        $grid->filter(function (Grid\Filter $filter) {
            $filter->equal('id');
            $filter->like('name');
            $filter->between('created_at')->datetime();
        });

        $grid->quickSearch('name', 'email');
        $grid->disableCreateButton(); // when appropriate
    });
}

Inline editing beats round-tripping to the edit form. ->switch(), ->editable(), and ->toggle() handle the common "flip a status" case without a controller change. These submit via AJAX using the grid's own update path, so keep field names aligned with real columns.

Column actions now accept a payload (2.2.3-beta). When you render a ->actions() entry from data, you can pass row context through instead of baking it into the URL:

$grid->actions(function (Grid\Displayers\Actions $actions) {
    $actions->append(
        new Grid\Actions\Action(
            'Publish',
            fn ($payload) => ...        // payload carried per-row
        )
    );
});

If you were string-building row actions before, this is the cleaner replacement for anything that previously interpolated IDs into a JS handler.

Form: use saving/saved hooks instead of controller code.

$form->text('name')->required();
$form->email('email')->required()
     ->rules(['required', 'email', Rule::unique('users', 'email')->ignore($form->model()->id)]);
$form->password('password')->minLength(8);
$form->select('role_id')->options(Role::pluck('name', 'id'));

$form->saving(function (Form $form) {
    if ($form->password && $form->password !== $form->model()->password) {
        $form->password = bcrypt($form->password);
    }
});

The $form->model() accessor (current record) and $form->isCreating()/$form->isEditing() cover nearly every conditional-field need, including $form->hidden() / $form->ignore() for fields that should never be persisted.

File/multi-file fields: the File field's multi-upload count limit was fixed in 2.2.3-beta — ->limit()/->max() was off-by-one (or ignored entirely) in older betas. If you shipped a workaround around the widget JS, remove it before upgrading.

Row and batch actions are the extension primitive. Generate with php artisan admin:action Post\\Publish --grid-row / --grid-batch / --detail-tool / --form-tool. Actions are self-contained classes with handle() and confirm()/dialog(); use them for anything with business logic (approve, resend, export a subset) rather than cramming more into saving. ->dialog() on a form action gives you a modal with a mini-form — very good for "reason for rejection" flows.

Detail page: Show::make($id, new User(), ...) with $show->field('col')->as(...), and $show->relation('orders', ...) for nested grids. Keep the detail page read-only and push mutations into actions.

Menus and RBAC are UI-managed database rows. Roles/permissions live in admin_roles, admin_permissions, admin_menu. Don't hardcode menu structure in code — build it in the UI so non-developers can reorder it. Permission checks in custom code: Admin::user()->can('users.edit') and Admin::user()->inRoles([...]).

Authorization is now first-class (2.2.3-beta). The Administrator model implements Laravel's Authorizable contract, so Admin::user()->can(), ->cannot(), ->canAny() and @can behave like any other authenticated model. Combine with the new authorization check on RenderableController (Show/detail pages and any custom renderables now enforce permissions) — meaning: assign permissions to existing roles after upgrading or users who previously saw detail widgets may suddenly be denied.

Custom pages: generate a controller, then return Admin::view('admin::your-view') or a Card/Box widget from Dcat\Admin\Widgets\*. For dashboard KPI cards, use Widgets\Metrics\Line|Bar|Doughnut|Card and wire data in app/Admin/Controllers/HomeController.php.

Integration tips: the admin area is a separate guard (admin) — do not expect Auth::user() to work inside admin pages. Share data via app/Admin/bootstrap.php (Admin::script(), Admin::css(), view composers) rather than editing vendor views. For per-locale JS strings, Admin::jsVariable() is now overridable — extend it in bootstrap.php to inject custom translations into the front-end instead of patching vendor lang files.

Gotchas and Tips

  • Maintenance risk — still beta. The latest tag is 2.2.3-beta; the project has never shipped a stable 2.x and has no official Laravel 11/12 branch. This package is deeply coupled to Laravel internals (route registration, pagination views, auth), so a major framework bump reliably breaks it. Pin laravel/framework to a supported major, pin dcat/laravel-admin to an exact beta, and budget time for a fork before bumping Laravel.
  • Upgrade checklist for 2.2.3-beta:
    • Re-check admin:install — it now runs migration files rather than issuing ad-hoc "create table" statements, so custom schema tweaks belong in migrations, not edits to the installer.
    • Grant permissions to existing roles — RenderableController now enforces authorization (see above). Silent 403s after upgrade are almost always this.
    • Re-enter form/table pages if you were compensating for the reversed sort icon (fixed) or the multi-file upload limit (fixed).
    • Re-test image fields inside embeds — uploads were being flagged as edits and saved unintentionally; that bug is fixed, so any custom "don't save the embed body" workaround can go.
  • Password re-hashing on update is the #1 first-week bug: an unedited password field submits the hash back and gets hashed again. Guard with the saving hook shown above, or $form->password('password')->ignore() on edit.
  • Unique validation needs a placeholder. Prefer Rule::unique(...)->ignore($form->model()->id) over the {{id}} string syntax — the string form is order-sensitive and silently wrong on create.
  • N+1 in grids. Any ->display() touching a relation loads per row. Declare $grid->model()->with(...) up front; the list view will otherwise hammer the DB at 50 rows/page.
  • Menu items are cached. After editing routes, permissions, or menu rows, items may not appear. Clear the app/admin cache (the menu page has a cache clear, and php artisan cache:clear fixes config-level staleness); also confirm the menu's URI exactly matches the controller action.
  • PJAX is always on. Inline <script> and $(document).ready() in custom views won't re-run on navigation. Use Admin::script() / Admin::scriptAfter() or bind to the pjax:complete event. This accounts for most "my JS works once then stops" reports.
  • Assets after upgrade: run php artisan admin:publish --force when the CSS/JS bundle changes; a stale public/vendor/dcat-admin produces ghost layout bugs. Same rule after every beta bump — the vendor bundle is not tracked by Composer.
  • Bootstrap 4 + jQuery front-end. If you reuse admin layouts in public-facing pages, or pull Bootstrap 5 components into admin views, you'll get conflicting resets. Isolate styles.
  • File/image fields need a real disk. Set config/admin.php upload.disk/directory and run php artisan storage:link; otherwise uploads succeed but render 404.
  • Backend conflicts bite too: Dcat registers broad middleware and its own exception handler for admin routes. Custom middleware in web that assumes JSON responses can break the grid's AJAX calls.
  • Extensions are a mixed bag. admin:import <vendor/package> registers them, but many extensions predate Laravel 9/10 — and almost none are tested against the current beta. Audit before depending on one; a small custom action/field is usually cheaper than debugging a stale plugin.
  • Debugging tip: Admin::disablePjax() (or setting a debug flag in app/Admin/bootstrap.php) makes normal full-page loads and browser devtools behave predictably — temporarily disable it when a bug is "invisible."
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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle