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)
- Authorization Behavior
- 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:
It also exposes an explicit contract interface, SingleRecordResolvableResource, for Resources that want first-class static-analysis support.
HasSingleRecordResource(Resource trait)
- Redirects index/navigation behavior to
view - Keeps sidebar navigation working without an
indexpage - Falls back to
viewauthorization on the resolved record whenviewAnyis denied - Exposes shared record resolution hooks on the Resource
- 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
- Prefers the Resource contract when available, while remaining compatible with legacy Resources that expose the same methods manually
- 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\Contracts\SingleRecordResolvableResource;
use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecordResource;
use Filament\Resources\Resource;
class MyWalletResource extends Resource implements SingleRecordResolvableResource
{
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.
For explicit static-analysis support, implement SingleRecordResolvableResource on Resources using HasSingleRecordResource. The package still accepts legacy Resources that define the same methods manually, but the interface is now the recommended public contract.
#Authorization Behavior
Filament normally uses viewAny() to decide whether a Resource can register navigation and be accessed at the Resource level.
For a root single-record resource, that default is too strict because there is no collection UX. This package now treats the Resource as accessible when:
viewAny()is allowed, orviewAny()is denied butview()is allowed for the resolved single record
This means a policy can intentionally deny listing while still allowing the user to open their own single record.
#Custom Resolution Strategies
If your rule is not a simple belongsTo(user), prefer overriding one of the methods below on the Resource so authorization and page loading stay aligned.
#A) Customize builder on the Resource (resolveSingleRecordBuilder)
public static function resolveSingleRecordBuilder(Builder $query): Builder
{
return parent::resolveSingleRecordBuilder($query)
->where('active', true);
}
#B) Full custom resolver on the Resource (resolveSingleRecord)
Use this when you need firstOrCreate, tenant logic, or complex business rules.
public static function resolveSingleRecord(): ?Model
{
/** @var \App\Models\User|null $user */
$user = filament()->auth()->user();
if ($user === null) {
return null;
}
return $user->wallet()->firstOrCreate([]);
}
#C) Optional page-specific override
If a specific ViewRecord/EditRecord page truly needs different resolution behavior than the Resource, you can still override the page methods:
protected function resolveSingleRecordBuilder(Builder $query): Builder
{
return parent::resolveSingleRecordBuilder($query)
->where('active', true);
}
#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
- Prefer implementing
SingleRecordResolvableResourceon Resources usingHasSingleRecordResourceso static analysis can understand the contract explicitly
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
Spotlight Pro
Browse your Filament Panel with ease. Filament Spotlight Pro adds a Spotlight/Raycast like Command Palette to your Filament Panel.
Dennis Koch
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