Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Dicebear Laravel Package

leek/filament-dicebear

DiceBear avatar provider for Filament panels, supporting all 31 DiceBear styles with caching, per-model customization, and self-hosted instances. Just register the plugin and provider to give users without custom avatars a generated DiceBear avatar.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire it up in three moves.

composer require leek/filament-dicebear
php artisan vendor:publish --tag=filament-dicebear-config

Then in your panel provider, two things must be registered — the provider (which Filament calls to resolve avatars) and the plugin (which carries configuration):

return $panel
    ->defaultAvatarProvider(DiceBearProvider::class)
    ->plugins([
        DiceBearPlugin::make()->style(DiceBearStyle::Thumbs),
    ]);

Run php artisan storage:link if you keep the default public disk — cached SVGs are written to storage/app/public/avatars/dicebear and served by URL. Without the symlink, avatars 404 silently and Filament falls back to its placeholder.

Where to look first:

  1. config/filament-dicebear.php — the global defaults. In a v2 install this is your source of truth for driver, format, style, options, animation, and cache; in a v1 install it is the flat key set (size, radius, scale, rotate, flip, background_color, background_type) shown in the README.
  2. Leek\FilamentDiceBear\Enums\DiceBearStyle — the canonical list of style slugs. Use the enum, not a raw string, so style('bottts-neutral') typos surface as a PHP-level failure rather than a silent Initials fallback.
  3. DiceBearPlugin — every fluent setter lives here; it is the fastest way to discover which options your installed version actually supports.

First use case worth shipping: drop the plugin into an existing panel and stop maintaining a placeholder avatar. Any User implementing Filament's HasAvatar that returns null from getFilamentAvatarUrl() will now get a deterministic, seeded, generated avatar. Zero schema changes, zero backfill, zero upload flow. That is the whole value proposition in one commit.

Implementation Patterns

Panel-level defaults, model-level overrides. Keep the plugin boring — one style for the whole panel — and let individual models opt into something else with the trait:

class User extends Model implements HasAvatar
{
    use HasDiceBearAvatar;

    public function dicebearAvatarStyle(): DiceBearStyle
    {
        return DiceBearStyle::Thumbs;
    }
}

The trait's real payoff is getCustomAvatarUrl(). Override it to prefer an uploaded photo and fall through to DiceBear:

protected function getCustomAvatarUrl(): ?string
{
    return $this->avatar_url ? Storage::url($this->avatar_url) : null;
}

This is the pattern most teams will actually run: real uploads where they exist, generated avatars everywhere else. Note the trait inherits panel-registered plugin config (baseUrl, apiVersion, cache settings) rather than constructing a fresh plugin — so a self-hosted URL set on the panel propagates into per-model avatars for free (fixed in v1.1.0; verify if you are on 1.0.x).

Multi-panel, multi-persona setups. A customer panel and an admin panel can legitimately want different styles. Register a differently configured DiceBearPlugin per panel and override dicebearAvatarStyle() only where the panel default is wrong. Because the provider is panel-scoped via defaultAvatarProvider(), you do not need one global answer.

Seed strategy. Default seed is the model id, which is stable and safe. Swap to email via seedUsing(fn ($record) => $record->email) when you want the same person to look identical across tenants/environments — but read the gotcha below before you do.

Style-specific options belong on the model, not the panel, when they encode identity (a bot style for service accounts, a person style for humans):

public function dicebearAvatarOptions(): array
{
    return ['eyes' => 'bulging,eva,happy', 'mouth' => 'smile01,smile02'];
}

Pick the driver intentionally. v2 renders natively in PHP by default via dicebear/core — no network, no rate limits, output byte-identical to the HTTP API. Use ->driver('http') only when you need raster output (->format('png')), a self-hosted instance, or a custom style definition. Native is the correct default for anything user-facing; HTTP is the right call for batch exports, PDFs, emails, and OG images where you need a real PNG/JPG/WEBP/AVIF.

Cache hygiene as an operational task. Cached SVGs live on a disk and are never automatically pruned. Add a scheduled cleanup if you allow per-model styles to drift:

Storage::disk('public')->deleteDirectory('avatars/dicebear');

v2 hashes options + DiceBear core/styles version into the filename, so config changes no longer serve stale images — but the old files linger. Treat the cache directory as a disposable artifact and clear it on deploy if you change styles.

Gotchas and Tips

The README and the release notes disagree — trust the release notes. The README documents v1.x: 31 styles, api_version => '9.x', percentage-based scale(), radius() and backgroundType(), and getters like getSize(). v2.0.0 ships 61 styles, 10.x, a 0–10 scale factor, removed getters (getCoreOption() instead), and deprecates radius(), backgroundType(), the gradientLinear string, 'true'/'false' for flip, flat config keys, and un-suffixed style options (eyes → eyesVariant). Run composer show leek/filament-dicebear before copying any snippet, and read UPGRADE.md before going 1.x → 2.x — cache filenames changed, so every existing avatar regenerates.

Seeds leak into the filesystem. Seeds are normalized with Str::slug(), which makes them filesystem-safe but not anonymous — a slugged email can end up in a cache path and therefore a public URL. If you seed by email, consider hashing it. id avoids the problem entirely.

Silent fallbacks hide misconfiguration. Invalid styles degrade to Initials via tryFrom(), and v2 routes invalid options to report() and falls back to an HTTP URL rather than throwing. Great for uptime, terrible for debugging: if avatars "look wrong but work," check storage/logs/laravel.log for reported exceptions and confirm the style slug exists in your installed enum.

Deprecations fire once per process. E_USER_DEPRECATED notices for the v2 deprecations won't repeat, which makes them easy to miss in a long-running worker. Grep your codebase for radius(, backgroundType(, and 'gradientLinear' as a one-off audit rather than relying on runtime noise.

Cold cache is a real cost on index pages. Native rendering is in-process, so a 50-row users table with an empty cache means 50 SVG generations inside one request. Warm the cache in a queue job or accept the first-hit latency; either way, do not disable caching (->cache(false)) in production — that path returns base64 data URIs, inflating every HTML response.

Disk visibility matters. Storage::url() on a private disk produces URLs the browser cannot fetch. Keep the avatar cache on public (or a CDN-backed public bucket) and double-check ->disk('public') survives your production config overrides.

Animation is opt-in and polite. v2's ->animated() activates the 19 animated styles; the CSS lives inside the SVG, so it plays in plain <img> tags and respects prefers-reduced-motion. Do not reach for it in dense tables — it is an empty-state / profile-page flourish.

Licensing is per-style, not per-package. The package is MIT, but several character styles are CC BY 4.0 and require attribution to the original artist. For a commercial product, either surface attribution in an about/credits page or standardise on CC0/MIT styles (thumbs, initials, shapes, rings, identicon, lorelei, notionists, open-peeps, pixel-art).

Testing. With the native driver there is no HTTP to fake — assert on the resolved URL and the presence of a cache file. Only reach for Http::fake() when you have explicitly set ->driver('http'). Remember to php artisan config:clear (or re-cache) after editing the published config, or your changes will appear to be ignored.

Extension point worth knowing: ->customStyle('brand', $path) accepts a DiceBear definition JSON. That is the escape hatch for a brand-locked avatar set without forking the package — and it is the most likely reason a team outgrows the built-in 61.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin