Laravel package for building
custom admin panels
Lean is an admin panel package focused on building fully customized admin panels for customers.
class OrderResource extends LeanResource
{
public $model = Order::class;
public $lang = [
'create.title' => 'Vytvořit objednávku',
];
public function fields()
{
return [...];
}
public function customActions()
{
return ['create' => CreateOrderAction::class];
}
}
Productive & Modern
Tech Stack
Everything you need
Built for your customers
Lean is a package focused entirely on building admin panels for humans. You can customize every last bit of it.
- Localization
- Every language string used by the package can be translated for each resource individually.
- Fast development
- Thanks to our bleeding-edge tech stack, you can build a custom-feeling admin panel extremely quickly.
- Clean code
- We don't generate any files. We don't pollute your codebase with repetitive boilerplate code. It's just resources + what you want custom.
- Modern design
- Lean ships with a modern & unopinionated theme. You're of course free (& encouraged) to customize the UI to match your brand. But if you're short on time — the default one will work great.
- Fields
- Lean ships with many fields out of the box, making it easy to implement your existing data model.
- Resources
- Each model gets a resource to tell Lean what fields, titles, labels, and translation strings to use.
- Pages
- Completely custom screens for when CRUD actions aren't good enough.
- Responsive
- Lean is an admin panel for humans — humans use a mobile — Lean is an admin panel for mobile.
class OrderResource extends LeanResource
{
public static string $model = Order::class;
public static array $searchable = [
'id',
];
public static string $title = 'id';
public static string $icon = 'heroicon-o-document-text';
}
Start with resources
Resources tell Lean how to talk to your database. Each resource has a model, searchable columns, a title column, icon, labels, and more.
Then add fields
Use fields to represent each database column, relationship, file, or any other data.
public static function fields(): array
{
return [
ID::make('id'),
Text::make('total')
->resolveValueUsing(
fn ($text, $model) => '$' . $model->total
)
->disabled()
->stored(false),
BelongsTo::make('customer')
->parent(CustomerResource::class)
->label(__('Buyer')),
HasMany::make('products')
->of(OrderProductResource::class)
->resultsPerPage(2)
->label(__('Products'))
->fields([
Text::make('name'),
Number::make('price'),
Number::make('quantity'),
Text::make('total')
->resolveValueUsing(
fn ($text, $model) => '$' . $model->total
),
]),
];
}
public static function customActions(): array
{
return [
'create' => CreateOrderAction::class,
];
}
use Lean\Livewire\Actions\LeanAction;
class CreateOrderAction extends LeanAction
{
public Order $order;
public Collection $availableProducts;
public array $products = [];
public $rules = [
'order.customer_id' => 'required|exists:customers,id',
'products.*.product_id' => 'required|exists:products,id',
'products.*.quantity' => 'required|numeric|min:1',
];
}
Replace actions
Boilerplate CRUD actions are great in 80% of cases, but sometimes you need that 20%. Lean lets you replace any CRUD action with your own componenet that's built in a way which makes sense to your customers.

Make it local
We've taken a completely different approach to localization than other admin panels. We don't have any complex inflection systems or anything like that. We simply let you and your translators specify language strings for each resource individually.
public static array $lang = [
'create.submit' => 'Vytvořit administrátora',
'create.title' => 'Vytvořit administrátora',
'edit.submit' => 'Upravit administrátora',
'edit.title' => 'Upravit administrátora :title',
];
public static function label(): string
{
return 'Administrátor';
}
public static function pluralLabel(): string
{
return 'Administrátoři';
}
class Statistics extends LeanPage
{
use WithNotifications;
public static function icon(): string
{
return 'heroicon-o-chart-bar';
}
public function generate()
{
$customer = Customer::cursor()->random();
$product = Product::cursor()->random();
$quantity = rand(1, 5);
$customer->orders()->create()->products()->create([
'product_id' => $product->id,
'quantity' => $quantity,
]);
$this->notify(
"{$customer->name} has purchased {$quantity}x {$product->name}"
);
}
}
Custom pages
Build pages from scratch and add them to your admin panel. CRUD actions work well for many things — and save a huge amount of time — but admin panels contain more than that.
Setting screens, dashboards, profile pages, permission pages, ...
Custom pages let you build anything you want, in any way you want, as long as you register the component in Lean as a page.

Mobile perfect
It's not just responsive, it's extremely mobile friendly.
- Responsivity
- Everything that works on desktop also works on mobile.
- Mobile menu
- The default bottom menu makes using Lean on mobile extremely productive, but sometimes you want to go even further than that. Lean lets you use a different bottom menu on each page.

Save resources the way you want
Use the flexible resource saving features that come out of the box, or build your own. Completely up to you.
- Backend: Customize how things are saved
-
On each resource, you can override the
update()
andcreate()
methods. They let you do any extra logic like a controller would. And of course, you can customize how individual fields are saved. - Frontend: Multiple options
- Let users select how they want to save the resource in the UI.
Questions & Answers
Ready to try it?
Get a license today.
We've just launched — $50 discount for a limited time. We've just launched and there's a big discount! Buy a license and get $50 off.