Single-Record Resource plugin screenshot
Dark mode ready
Multilingual support
Supports v5.x

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.

Tags: Panels
Supported versions:
5.x 4.x
Argemiro Dias avatar Author: Argemiro Dias

Documentation

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

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:

  1. HasSingleRecordResource (Resource trait)
  • Redirects index/navigation behavior to view
  • Keeps sidebar navigation working without an index page
  • Helps nested resources resolve root URLs/slugs in single-record chains
  1. HasSingleRecord (Page trait for ViewRecord and EditRecord)
  • 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 Wallet
  • Wallet 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):

  1. Keep HasSingleRecordResource on resources that follow the single-record flow
  2. Keep HasSingleRecord in deep ViewRecord/EditRecord pages
  3. 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)

MyWallet page

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

Deep nested product page

#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.

The author

Argemiro Dias avatar Author: Argemiro Dias

Brazilian Civil Engineer and Laravel developer focused on building tools and plugins for the Filament ecosystem. Passionate about creating solutions that simplify complex workflows and improve the developer experience in modern PHP applications.

Plugins
2
Stars
7