Filament is a Laravel package for building admin panels: the screens where your team creates, edits, approves and reports on the records behind a product. This article is for developers and technical leads deciding whether to use it for a real internal tool with many users, roles and languages. Our position, after using it on bilingual content sites and back-office systems, is that it is the right default for most Laravel admin work and the wrong tool for a handful of specific cases. Knowing which is which up front saves a rewrite.
When does Filament beat a custom admin panel?
A custom admin is a second application. It needs its own auth, layout, tables, filters, forms, validation messages, file uploads, bulk actions and permission checks, and every one of them is a place where a bug can hide. Filament gives you all of that out of the box on top of Livewire and Tailwind, so a working CRUD screen for a model is an afternoon rather than a sprint.
It wins whenever the admin is a means, not the product. Content management, order handling, support tools, approval workflows, back-office data entry: the people using these screens want them fast and predictable, not distinctive.
Build a custom admin instead when the interface is the product, when the interaction model is not "list, filter, edit a record" (a drag-and-drop planner, a live dashboard with real-time collaboration), or when the admin must be embedded inside a front end that is already React or Next.js and a second UI stack is unacceptable.
How should you structure Filament resources and forms?
A resource is Filament's unit of work: one class describing the table, the form and the pages for a model. Keep resources thin. The form schema and table columns belong in the resource; validation that expresses business rules belongs in the Form Requests or model methods you already have, so the API and the admin cannot drift apart.
A few habits pay off:
- Name form sections after what the editor is doing, not after database columns. "Publishing" with status and date reads better than "Meta".
- Use relation managers for child records instead of nesting them in the parent form. A post with its comments is two screens, not one long one.
- Use actions for anything that is not "save": publish, archive, resend, export. Each is a named button with its own authorization and confirmation, and it keeps the form free of hidden state changes.
- Write a test for each resource that at least loads the list page and submits the form. Filament ships Livewire testing helpers, and a broken admin found by the client is worse than one found by CI.
How do roles and permissions work in Filament?
Filament does not ship its own permission model, and that is a good decision: it uses Laravel policies. If a PostPolicy says a user may not delete, the delete button disappears and the request is refused. So the first step is the same as in any Laravel application: write policies for every model the panel exposes.
For named roles, pair it with spatie/laravel-permission and a small plugin that exposes roles and permissions as resources of their own. Keep the roles few and the permissions verbs: update posts, publish posts, not one permission per screen. Restrict panel access itself with the FilamentUser contract so that a customer account can never reach the admin login, and use separate panels rather than one giant one when two audiences need genuinely different navigation.
Do not hide navigation and call that security: a hidden menu item is still a reachable URL. Policies are the enforcement.
How do you handle bilingual content in Filament?
Most of our clients publish in English and Arabic, so every translatable field in our panels is a tab per locale. With spatie/laravel-translatable and Filament's translatable plugin, a JSON column becomes an English tab and an Arabic tab on the same form, with the default locale first because it is the fallback.
Three details matter more than the plugin choice. First, right-to-left: the Arabic tab needs dir="rtl" on its inputs and the rich editor, or editors will fight the cursor. Second, per-locale validation: a required title should be required in the primary locale and optional in the other, or nothing can be drafted. Third, partial saves: make sure saving one tab never wipes the other, and put a test on it, because that failure is silent and is found by a visitor rather than an editor.
Where are Filament's limits?
Filament is Livewire, so every interaction is a server round trip. Screens with hundreds of inputs, very large tables without server-side pagination, or anything that needs instant feedback will feel heavy. It is also opinionated about layout; deep theming is possible but works against it, and the moment you are overriding Blade views for most components you have started building a custom admin with extra steps.
Be honest about the audience: Filament is a superb tool for a staff panel and a poor fit for a consumer-facing portal, where a public Next.js front end against the same Laravel API serves better. On our projects the split is usually exactly that: Filament for the team, Next.js for everyone else, one API underneath both.