ITSkillsCenter
Blog

Laravel Filament : back-office rapide en pratique

14 دقائق للقراءة

Lecture : 13 minutes · Niveau : intermédiaire · Mise à jour : avril 2026

Filament a pris une place centrale dans l’écosystème Laravel : il génère des back-offices professionnels en quelques heures, là où il en aurait fallu des semaines avec un développement custom. Pour une PME, c’est souvent la différence entre livrer un MVP en deux semaines ou en deux mois. Ce guide montre comment exploiter Filament efficacement sans tomber dans les pièges classiques.

L’argument économique de Filament est simple : la grande majorité des back-offices se ressemblent. Ils ont des listes paginées avec recherche et filtres, des formulaires avec validation, des écrans de détail, des actions sur enregistrements (envoyer un email, archiver, valider une commande). Réécrire ces patterns à chaque projet est du gaspillage. Filament les industrialise sans sacrifier la possibilité de customisation profonde quand un cas métier le justifie.

L’investissement initial est l’apprentissage de l’API Filament : quelques jours pour les bases, quelques semaines pour la maîtrise des composants avancés. Cet investissement est ensuite amorti sur tous les futurs back-offices de l’équipe — un gain composé qui dépasse rapidement le coût d’apprentissage. Pour les équipes Laravel qui livrent régulièrement des applications métier, c’est devenu un outil aussi structurant que Eloquent ou Blade dans la stack standard.

Voir aussi → Laravel pour PME : guide backend PHP moderne.


Sommaire

  1. Pourquoi Filament en 2026
  2. Installation et premier panel
  3. Resources : CRUD complet en 1 commande
  4. Forms : champs et validation
  5. Tables : colonnes, filtres, actions
  6. Dashboards et widgets
  7. Pages custom et actions globales
  8. Permissions et multi-rôles
  9. Multi-tenancy
  10. Déploiement et performance
  11. FAQ

1. Pourquoi Filament en 2026

Filament (filamentphp.com) génère des interfaces d’administration depuis Eloquent. C’est un panel admin construit sur Livewire, Alpine.js et Tailwind, conçu pour la productivité.

Avantages clés

  • Productivité spectaculaire : un CRUD complet (liste, recherche, filtres, pagination, création, édition, suppression) en quelques minutes
  • Customisation totale : tout est en PHP, modifiable, surchargeable
  • UX moderne : interface propre, responsive, dark mode, accessible
  • Pas de framework JS séparé : tout est PHP/Blade via Livewire
  • Écosystème de plugins : nombreux packages communautaires (audit logs, médias, traductions, etc.)
  • Documentation excellente et communauté très active

Cas d’usage idéaux

  • Back-office d’application Laravel (gestion de clients, commandes, contenus)
  • Dashboards pour équipes métier
  • MVPs qui ont besoin d’une admin avant tout autre chose
  • SaaS B2B avec espace admin pour les locataires

Limites

  • Front-office public : Filament n’est pas conçu pour ça (utiliser Blade/Livewire/Inertia classique)
  • UX très spécifiques : si on doit construire une UI radicalement différente de Filament, partir d’autre chose
  • Apprentissage de l’API Filament : pour exploiter pleinement, il faut investir quelques jours

2. Installation et premier panel

composer require filament/filament
php artisan filament:install --panels

Crée un panel admin accessible sur /admin.

Créer le premier utilisateur admin

php artisan make:filament-user

Demande nom, email, mot de passe. Crée un utilisateur avec accès au panel.

Configuration du panel

app/Providers/Filament/AdminPanelProvider.php est généré. Modifications courantes :

public function panel(Panel $panel): Panel
{
    return $panel
        ->default()
        ->id('admin')
        ->path('admin')
        ->login()
        ->colors([
            'primary' => Color::Blue,
        ])
        ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
        ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
        ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
        ->middleware([
            EncryptCookies::class,
            // ...
        ])
        ->authMiddleware([
            Authenticate::class,
        ]);
}

Plusieurs panels possibles : un pour admin, un pour utilisateurs métier, un pour clients. Architecture multi-panel native.


3. Resources : CRUD complet en 1 commande

php artisan make:filament-resource Client --generate

Le flag --generate introspecte le modèle Eloquent et génère automatiquement les champs du form et de la table. Édition possible ensuite.

namespace App\Filament\Resources;

use Filament\Resources\Resource;
use Filament\Forms\Form;
use Filament\Tables\Table;
use Filament\Forms;
use Filament\Tables;
use App\Models\Client;

class ClientResource extends Resource
{
    protected static ?string $model = Client::class;
    protected static ?string $navigationIcon = 'heroicon-o-users';
    protected static ?string $navigationGroup = 'Commercial';
    protected static ?int $navigationSort = 1;
    protected static ?string $recordTitleAttribute = 'nom';

    public static function form(Form $form): Form
    {
        return $form->schema([
            Forms\Components\TextInput::make('nom')
                ->required()
                ->maxLength(100),
            Forms\Components\TextInput::make('email')
                ->email()
                ->required()
                ->unique(ignoreRecord: true),
            Forms\Components\TextInput::make('telephone'),
            Forms\Components\Toggle::make('actif')->default(true),
        ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make('nom')->searchable()->sortable(),
                Tables\Columns\TextColumn::make('email')->copyable(),
                Tables\Columns\IconColumn::make('actif')->boolean(),
                Tables\Columns\TextColumn::make('created_at')->date()->sortable(),
            ])
            ->filters([
                Tables\Filters\TernaryFilter::make('actif'),
            ])
            ->actions([
                Tables\Actions\EditAction::make(),
                Tables\Actions\DeleteAction::make(),
            ])
            ->bulkActions([
                Tables\Actions\BulkActionGroup::make([
                    Tables\Actions\DeleteBulkAction::make(),
                ]),
            ]);
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListClients::route('/'),
            'create' => Pages\CreateClient::route('/create'),
            'edit' => Pages\EditClient::route('/{record}/edit'),
        ];
    }
}

Le résultat est un CRUD complet avec :
– Liste paginée avec recherche et tri sur les colonnes marquées
– Filtres (ici sur le champ actif)
– Création et édition via formulaire
– Suppression individuelle et en masse
– Navigation organisée par groupe


4. Forms : champs et validation

Filament offre une trentaine de composants de formulaire prêts à l’emploi.

public static function form(Form $form): Form
{
    return $form->schema([
        Forms\Components\Section::make('Informations principales')
            ->columns(2)
            ->schema([
                Forms\Components\TextInput::make('nom')->required()->maxLength(100),
                Forms\Components\TextInput::make('email')->email()->required(),
                Forms\Components\Select::make('country_id')
                    ->relationship('country', 'name')
                    ->searchable()
                    ->required(),
                Forms\Components\TextInput::make('telephone')
                    ->tel()
                    ->mask('+221 99 999 99 99'),
            ]),
        Forms\Components\Section::make('Adresse')
            ->columns(2)
            ->collapsible()
            ->schema([
                Forms\Components\Textarea::make('rue')->rows(2)->columnSpanFull(),
                Forms\Components\TextInput::make('ville'),
                Forms\Components\TextInput::make('code_postal'),
            ]),
        Forms\Components\Section::make('Avancé')
            ->collapsed()
            ->schema([
                Forms\Components\Toggle::make('actif')->default(true),
                Forms\Components\KeyValue::make('metadata'),
                Forms\Components\FileUpload::make('logo')
                    ->image()
                    ->directory('logos'),
            ]),
    ]);
}

Validation

Les validations Laravel standard fonctionnent :

Forms\Components\TextInput::make('email')
    ->email()
    ->required()
    ->unique(ignoreRecord: true)
    ->rules(['confirmed']),

Conditional fields :

Forms\Components\Select::make('type')
    ->options(['individual' => 'Individuel', 'business' => 'Entreprise'])
    ->live(),
Forms\Components\TextInput::make('siret')
    ->visible(fn (Get $get) => $get('type') === 'business'),

live() rend le champ réactif. Les autres champs peuvent dépendre de sa valeur.

Wizards (formulaires multi-étapes)

Forms\Components\Wizard::make([
    Forms\Components\Wizard\Step::make('Identité')->schema([...]),
    Forms\Components\Wizard\Step::make('Coordonnées')->schema([...]),
    Forms\Components\Wizard\Step::make('Préférences')->schema([...]),
])

Idéal pour des formulaires longs ou des onboarding utilisateur.


5. Tables : colonnes, filtres, actions

public static function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\ImageColumn::make('logo')->circular(),
            Tables\Columns\TextColumn::make('nom')
                ->searchable()
                ->sortable()
                ->weight('bold'),
            Tables\Columns\TextColumn::make('email')->copyable(),
            Tables\Columns\TextColumn::make('orders_count')
                ->counts('orders')
                ->badge(),
            Tables\Columns\TextColumn::make('total_ca')
                ->money('XOF')
                ->summarize(Sum::make()),
            Tables\Columns\TextColumn::make('country.name')
                ->label('Pays'),
            Tables\Columns\IconColumn::make('actif')->boolean(),
            Tables\Columns\TextColumn::make('created_at')
                ->date('d/m/Y')
                ->sortable()
                ->toggleable(),
        ])
        ->filters([
            Tables\Filters\TernaryFilter::make('actif'),
            Tables\Filters\SelectFilter::make('country')
                ->relationship('country', 'name')
                ->searchable(),
            Tables\Filters\Filter::make('created_at')
                ->form([
                    Forms\Components\DatePicker::make('from'),
                    Forms\Components\DatePicker::make('until'),
                ])
                ->query(function (Builder $query, array $data) {
                    return $query
                        ->when($data['from'], fn ($q, $date) => $q->whereDate('created_at', '>=', $date))
                        ->when($data['until'], fn ($q, $date) => $q->whereDate('created_at', '<=', $date));
                }),
        ])
        ->actions([
            Tables\Actions\ViewAction::make(),
            Tables\Actions\EditAction::make(),
            Tables\Actions\Action::make('relance')
                ->icon('heroicon-o-envelope')
                ->action(fn (Client $record) => $record->envoyerRelance())
                ->requiresConfirmation(),
        ])
        ->bulkActions([
            Tables\Actions\BulkActionGroup::make([
                Tables\Actions\DeleteBulkAction::make(),
                Tables\Actions\BulkAction::make('export')
                    ->icon('heroicon-o-arrow-down-tray')
                    ->action(fn ($records) => Excel::download(new ClientsExport($records), 'clients.xlsx')),
            ]),
        ])
        ->defaultSort('nom');
}

Possibilités énormes : group by, summarize, export Excel/CSV, actions custom, modales, etc.


6. Dashboards et widgets

Le panel a une page d’accueil avec widgets. On peut en créer.

Widget de stats

php artisan make:filament-widget StatsOverview --stats-overview
class StatsOverview extends BaseWidget
{
    protected function getStats(): array
    {
        return [
            Stat::make('Clients actifs', Client::where('actif', true)->count())
                ->description('Total comptes actifs')
                ->color('success'),
            Stat::make('Commandes ce mois', Order::whereMonth('created_at', now())->count())
                ->chart([7, 12, 18, 14, 22, 28, 35])
                ->color('primary'),
            Stat::make('CA mensuel', number_format(Order::whereMonth('created_at', now())->sum('total'), 0, ',', ' ') . ' F CFA')
                ->color('warning'),
        ];
    }
}

Widget chart

php artisan make:filament-widget VentesChart --chart
class VentesChart extends ChartWidget
{
    protected static ?string $heading = 'Ventes 30 derniers jours';

    protected function getData(): array
    {
        $data = Order::query()
            ->selectRaw('DATE(created_at) as jour, SUM(total) as ca')
            ->where('created_at', '>=', now()->subDays(30))
            ->groupBy('jour')
            ->orderBy('jour')
            ->get();

        return [
            'datasets' => [['label' => 'CA', 'data' => $data->pluck('ca')]],
            'labels' => $data->pluck('jour'),
        ];
    }

    protected function getType(): string { return 'line'; }
}

Combinés à des widgets de tables (top clients, dernières commandes), un dashboard complet en quelques heures.

Pour des dashboards plus exigeants, on peut combiner widgets natifs et des graphiques tiers comme ApexCharts ou Chart.js intégrés via composants Livewire. Le panel admin devient un outil de pilotage métier au-delà du simple back-office CRUD. Les équipes commerciales et de direction y trouvent souvent leur tableau de bord opérationnel quotidien, là où elles passaient avant par des exports Excel manuels et des tableaux croisés dynamiques fragiles.


7. Pages custom et actions globales

Pour des écrans qui ne sont pas du CRUD, créer des pages custom :

php artisan make:filament-page Reporting
class Reporting extends Page
{
    protected static ?string $navigationIcon = 'heroicon-o-chart-bar';
    protected static string $view = 'filament.pages.reporting';

    public function getViewData(): array
    {
        return [
            'totalCa' => Order::sum('total'),
            'topClients' => Client::withSum('orders', 'total')
                ->orderByDesc('orders_sum_total')
                ->take(10)
                ->get(),
        ];
    }
}

Templates Blade libres, on dessine ce qu’on veut. Idéal pour des reportings spécifiques.


8. Permissions et multi-rôles

Filament s’intègre nativement avec spatie/laravel-permission.

composer require spatie/laravel-permission
composer require bezhanSalleh/filament-shield

Filament Shield

Shield génère automatiquement les permissions pour chaque resource Filament et fournit une UI pour gérer rôles et permissions.

php artisan shield:install
php artisan shield:generate --all

Permissions générées : view_any_client, view_client, create_client, update_client, delete_client, etc.

Configurer un User comme HasShield

class User extends Authenticatable implements FilamentUser
{
    use HasRoles;

    public function canAccessPanel(Panel $panel): bool
    {
        return $this->hasRole(['admin', 'manager']);
    }
}

Restrictions par resource

public static function canViewAny(): bool
{
    return auth()->user()->can('view_any_client');
}

Combiné aux Policies Laravel, contrôle d’accès robuste à l’échelle de l’application.


9. Multi-tenancy

Filament supporte nativement le multi-tenancy depuis la v3.

public function panel(Panel $panel): Panel
{
    return $panel
        ->default()
        ->tenant(Team::class)
        ->tenantMenu()
        ->tenantRegistration(RegisterTeam::class);
}

Chaque utilisateur peut avoir plusieurs « tenants » (équipes, organisations, espaces). Le panel affiche un sélecteur en haut, et toutes les ressources sont automatiquement filtrées par tenant.

class Client extends Model
{
    public function team()
    {
        return $this->belongsTo(Team::class);
    }
}

// Le filtrage par tenant est automatique

Pour un SaaS B2B avec espaces clients séparés, Filament rend cette architecture trivialement implémentable, ce qui en fait un atout différenciant pour les équipes qui visent ce type de modèle économique.


10. Déploiement et performance

Filament étant une couche au-dessus de Laravel, le déploiement suit les mêmes règles. Voir Laravel déploiement production.

Quelques optimisations spécifiques

  • Cache des routes Filament : php artisan filament:cache-components après modification
  • Eager loading dans les tables : ->with(['relation']) dans la query du resource pour éviter N+1
  • Limite raisonnable des records par page : 25-50 par défaut, augmenter avec parcimonie
public static function getEloquentQuery(): Builder
{
    return parent::getEloquentQuery()
        ->with(['country', 'orders']);  // eager load
}

Assets

php artisan filament:assets

Régénère les assets (CSS, JS) après installation de plugins. À intégrer au pipeline CI/CD.


11. FAQ

Filament remplace-t-il un framework JS comme React ?

Non, ils ne servent pas le même but. Filament génère un back-office. React/Vue construisent des applications custom (front public, app mobile, dashboards très spécifiques). Pour un back-office Laravel : Filament. Pour une app publique : Livewire/Inertia/React selon contexte.

Filament est-il gratuit ?

Oui, le core est open-source MIT. Certains plugins officiels avancés (Tables Pro, Forms Pro avec features supplémentaires) sont payants. La quasi-totalité des cas PME est couverte par le gratuit.

Combien de temps pour livrer un back-office Filament ?

Pour 5-10 modèles avec CRUD standard : 1-3 jours d’un développeur Laravel correct. Pour 20+ modèles avec workflows custom, dashboards, permissions fines : 1-3 semaines. Bien plus rapide qu’un dev custom from-scratch.

Filament fonctionne-t-il sur de la grosse volumétrie ?

Pour les listes : avec eager loading et indexation correcte, plusieurs millions de lignes restent gérables. Pour les dashboards avec aggregations massives : préférer du cache (Redis) sur les requêtes coûteuses.

Personnalisation visuelle profonde ?

Oui, Tailwind sous-jacent permet beaucoup de customisation via colors, theme, et CSS custom. Pour un branding complet, c’est faisable mais demande plus d’effort que la customisation minimale.

Comment intégrer un workflow personnalisé (ex: validation en plusieurs étapes) ?

Combiner : Actions Filament (boutons custom), Form wizards (étapes), Pages custom, et Eloquent Observers pour la logique métier. Filament expose des hooks à chaque étape de la vie d’un record.

Filament + multi-langue ?

Oui via astrotomic/laravel-translatable ou spatie/laravel-translatable. Filament a des composants spécifiques pour gérer les champs traduits. Largement utilisé en production multilingue.


Articles liés (cluster Laravel)


Article mis à jour le 25 avril 2026. Pour signaler une erreur ou suggérer une amélioration, écrivez-nous.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité