hollyit/filament-static-assets
Filament Static Assets adds a simple asset manager to your Filament admin panel. Browse, upload, organize, and delete static files in public directories, so images, CSS, JS, fonts, and other resources stay tidy. Manage everything from a dedicated Filament page without leaving Laravel.
This package exists to solve one narrow problem: Filament normally serves its compiled CSS/JS through Laravel routes (or from the vendor directory), which means every asset request hits PHP. hollyit/filament-static-assets lets those files live under /public so nginx/Apache (or a CDN) can serve them directly. Reach for it when you're deploying behind a reverse proxy, running in Docker where the public directory is the only writable/servable path, or you want long-lived cache headers on Filament's assets without touching PHP.
Minimal steps:
composer.json requirement matches your Filament major version (v2 vs v3) before committing:
composer require hollyit/filament-static-assets
php artisan vendor:publish --tag="filament-static-assets-config"
filament-static-assets:* or filament:* namespace). This is what copies the compiled Filament assets into public/.public/, then hard-refresh the admin panel and check the Network tab — you should see asset URLs pointing at /public/... paths rather than /filament/assets/... route URLs.php artisan config:clear && php artisan view:clear.The first real use case to try is a production deploy: run the publish command as part of your deploy script, then confirm with curl -I https://yourapp.test/<published-asset-path> that the response comes back 200 from your web server (check the Server header) rather than through Laravel.
Deploy-time publishing, not runtime. Treat the publish step like npm run build — it belongs in CI or your deploy script, not in a request lifecycle. A typical ordering is:
composer install --no-dev --optimize-autoloader
php artisan filament-static-assets:publish # verify exact name in README
php artisan config:cache
php artisan route:cache
php artisan view:cache
Docker multi-stage builds. Run the publish command during the build stage so the assets are baked into the image layer. This gives you immutable images and lets you serve public/ from a read-only filesystem at runtime. Pair it with a health check that requests one of the published asset URLs.
Pairing with a CDN. Because the assets now have real filesystem paths under public/, you can front them with CloudFront/Cloudflare and apply aggressive Cache-Control: public, max-age=31536000, immutable on the asset directory only, leaving the rest of the app on normal cache rules. This is the strongest reason to adopt the package — it turns Filament's assets into ordinary static files your CDN already knows how to handle.
Local vs. production split. In local, Filament's default route-based serving is fine and avoids stale-copy confusion. Gate the publish step to non-local environments in your deploy tooling so developers never have to remember to re-run it after every composer update.
Multi-panel setups. If you run several Filament panels (admin, staff, etc.), confirm the package publishes assets for each panel's registered asset set, or run the publish command once and verify every panel renders correctly — panels with different path() prefixes or custom themes may not be covered by a single pass.
Theming and custom CSS. If you publish a custom Filament theme, publish it after this package's step so your compiled theme overwrites anything it might collide with, and double-check the resulting public directory for duplicate or orphaned files.
Stale assets are the #1 failure mode. Once copied into public/, the files are decoupled from the vendor directory. Every composer update that bumps Filament can leave you serving last month's CSS/JS. Wire the publish command into post-update-cmd in composer.json, or into the same script that runs composer install in CI, and add a CI check that fails if public/<asset-dir> is older than composer.lock.
Don't commit the published assets. Add the output directory to .gitignore. Committing it creates merge conflicts, balloons the repo, and — worse — makes it easy to ship an image where someone forgot to re-publish and the committed copy silently shadows the correct one.
Version compatibility is the real risk. With 15 stars and a single release from early 2023, this package is unlikely to be tracking Filament v3+ actively. Before adopting: check the composer.json constraints, test against your exact Filament version, and be prepared to vendor/fork the small amount of logic if Filament changes its asset registration API. For many teams, php artisan filament:assets plus a symlink from public/ into the vendor directory achieves the same result with zero third-party dependency — evaluate that before adding the package.
Cache-busting. Filament appends query strings or hashes to asset URLs; when you move to static serving your web server may strip or ignore them. Verify that a hard refresh after deploy actually pulls the new file. If not, either enable Filament's versioned asset paths or configure your CDN to key on the full query string.
Subdirectory deployments. If the app lives under a path prefix (e.g. https://example.com/admin-app/), the published asset URLs need to respect ASSET_URL / APP_URL. Test this explicitly — hardcoded /-rooted paths are a common bug in small asset-publishing packages. Setting ASSET_URL correctly usually fixes it.
Permissions. The publish command writes into public/, which in hardened deployments is often read-only at runtime. Either run it at build time (preferred) or ensure the directory is writable during deploy and locked down afterward.
Debugging checklist when styles break after install:
php artisan route:list | grep filament — did the route-based asset serving get disabled?<link>/<script> tags pointing at public paths or the old route paths?ls -la public/<asset-dir> — do files exist and are they non-zero?curl -I the asset URL — 404 means the web server root or path is wrong; 200 through PHP means the package's URL rewriting didn't apply.php artisan config:clear after editing the published config — config caching will otherwise mask your changes.Extension points. The published config file is your lever for the asset output path and any enable/disable flag. If you need conditional behavior (e.g. skip publishing when a CDN origin already has the assets), wrap the artisan command in your own deploy script rather than modifying the package — this keeps upgrades trivial and makes it easy to drop the package later if Filament adds native support.
How can I help you explore Laravel packages today?