Single-Record Resource
A Filament plugin that solves the single-record resource pattern — resources that display exactly one record per authenticated user (e.g. "My Profile", "My Wallet", "My Settings") without an index page, and their arbitrarily nested child resources.
Author:
Argemiro Dias
Documentation
- Compatibility
- Installation
- Core Concepts
- Step-by-Step Implementation
- Automatic Record Resolution (1:1 with authenticated user)
- Custom Resolution Strategies
- Nested Resources
- Screenshots
- Testing
- Changelog
- Contributing
- Security
- Credits
- License
This package implements the single-record resource pattern for Filament panels.
Instead of a list page (index) with many records, you open one resource that always resolves to one business record per authenticated user.
Common examples:
- My Profile
- My Wallet
- My Settings
- Current Subscription
#Compatibility
- Filament
^4.0 || ^5.0 - Laravel versions supported by the selected Filament major
#Installation
composer require coringawc/filament-single-record-resource
#Core Concepts
This package is based on two traits:
HasSingleRecordResource(Resource trait)
- Redirects index/navigation behavior to
view - Keeps sidebar navigation working without an
indexpage - Helps nested resources resolve root URLs/slugs in single-record chains
HasSingleRecord(Page trait forViewRecordandEditRecord)
- Resolves the root single record automatically
- Supports custom resolution via builder or custom resolver method
- Normalizes breadcrumbs in deep nested resources
#Step-by-Step Implementation
#1. Create your resource as single-record root
In your Filament Resource, use HasSingleRecordResource and register only view (and optionally edit) pages.
<?php
namespace App\Filament\Resources\MyWallets;
use App\Filament\Resources\MyWallets\Pages\EditMyWallet;
use App\Filament\Resources\MyWallets\Pages\ViewMyWallet;
use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecordResource;
use Filament\Resources\Resource;
class MyWalletResource extends Resource
{
use HasSingleRecordResource;
public static function getPages(): array
{
return [
'view' => ViewMyWallet::route('/'),
'edit' => EditMyWallet::route('/edit'),
];
}
}
#2. Use HasSingleRecord in ViewRecord
<?php
namespace App\Filament\Resources\MyWallets\Pages;
use App\Filament\Resources\MyWallets\MyWalletResource;
use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecord;
use Filament\Resources\Pages\ViewRecord;
class ViewMyWallet extends ViewRecord
{
use HasSingleRecord;
protected static string $resource = MyWalletResource::class;
}
#3. Optional: also use HasSingleRecord in EditRecord
Yes, this package supports EditRecord too.
<?php
namespace App\Filament\Resources\MyWallets\Pages;
use App\Filament\Resources\MyWallets\MyWalletResource;
use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecord;
use Filament\Resources\Pages\EditRecord;
class EditMyWallet extends EditRecord
{
use HasSingleRecord;
protected static string $resource = MyWalletResource::class;
}
#Automatic Record Resolution (1:1 with authenticated user)
By default, HasSingleRecord calls a builder that applies whereBelongsTo(Filament::auth()->user()).
In practice, this works automatically when your resource model has a belongsTo(User::class) relation that points to the authenticated Filament user.
Typical 1:1 setup:
User hasOne WalletWallet belongsTo User
Example model relationships:
// App\Models\User
public function wallet(): HasOne
{
return $this->hasOne(Wallet::class);
}
// App\Models\Wallet
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
With this, your single-record root page resolves the wallet for the logged-in user automatically.
#Custom Resolution Strategies
If your rule is not a simple belongsTo(user), override one of the methods below in the page class.
#A) Customize builder (resolveSingleRecordBuilder)
protected function resolveSingleRecordBuilder(Builder $query): Builder
{
return parent::resolveSingleRecordBuilder($query)
->where('active', true);
}
#B) Full custom resolver (resolveSingleRecord)
Use this when you need firstOrCreate, tenant logic, or complex business rules.
protected function resolveSingleRecord(): ?Model
{
/** @var \App\Models\User|null $user */
$user = filament()->auth()->user();
if ($user === null) {
return null;
}
return $user->wallet()->firstOrCreate([]);
}
#Nested Resources
For nested chains (for example MyWallet -> Companies -> Products):
- Keep
HasSingleRecordResourceon resources that follow the single-record flow - Keep
HasSingleRecordin deepViewRecord/EditRecordpages - If removing parent IDs from URLs, enforce strict query scoping in your models/pages
This package also helps preserve breadcrumb consistency in deep nested routes.
#Screenshots
#MyWallet (Root Single Resource)

#Deep Nested Resource (MyWallet -> Companies -> Products)

#Testing
Run tests:
composer test
The package CI validates the plugin in two scenarios:
- Filament 4 latest stable in major
- Filament 5 latest stable in major
#Changelog
Please see CHANGELOG for details.
#Contributing
Please see CONTRIBUTING.
#Security
Please review our security policy.
#Credits
#License
The MIT License (MIT). See LICENSE.md.
Featured Plugins
A selection of plugins curated by the Filament team
Custom Dashboards
Let your users build and share their own dashboards with a drag-and-drop interface. Define your data sources in PHP and let them do the rest.
Filament
Custom Fields
Eliminate custom field migrations forever. Let your users create and manage form fields directly in Filament admin panels with 20+ built-in field types, validation, and zero database changes.
Relaticle
Advanced Tables (formerly Filter Sets)
Supercharge your tables with powerful features like user-customizable views, quick filters, multi-column sorting, advanced table searching, convenient view management, and more. Compatible with Resource Panel Tables, Relation Managers, Table Widgets, and Table Builder!
Kenneth Sese