3x1io/filament-excel
3x1io/filament-excel is a Filament plugin that adds Excel import and export workflows to Laravel admin panels, with customizable columns, queued processing, and simple resource actions for managing spreadsheet data.
The package is a Filament plugin that wires Excel export/import into panel resources, so the fastest path to value is to attach it to one existing Resource rather than building a new one.
composer require 3x1io/filament-excel (v1.0.1 or later — the plural-name fix in this release affects generated headings, so don't pin v1.0.0).php artisan vendor:publish --tag=filament-excel-config.->plugin(FilamentExcelPlugin::make())) if the version you installed exposes one; otherwise skip straight to step 4 — many builds of this package are action-based and need no provider registration.src/Actions (or src/Exports / src/Imports) directory to see which Filament action classes are exposed, and at the config file for the export/import defaults. Those two things tell you more about real capability than the README.ListRecords/ManageRecords page or a table header action for a simple model, download the file, and confirm column headings and date/number formatting match expectations. Then repeat the exercise for an import on a staging database before touching production.Table header export as the default. Attach the export action to the table rather than to a page action so it inherits current filters, search, and sort. Verify explicitly whether the action exports the filtered query or the raw model query — the two behave very differently for large tables and for user trust.
Queued exports for anything non-trivial. For large datasets, wire the export to a queued job and notify the user (database notification + Filament notification) when the file is ready on the configured disk. Keep the disk configurable per environment: local/S3 for dev, private S3 with signed URLs in production.
Import as a two-step flow. Don't let users import straight into the model. Pattern that holds up: upload → validate & preview the first N rows against your column mapping → confirm → dispatch an import job that writes row-by-row with per-row error collection, then surface a summary (created/updated/failed) as a notification or a small report page. This is where most of your integration work will go; the package gives you the file handling, not your business rules.
Column mapping as config, not code. Define export columns and import mappings in a dedicated class or array keyed by field name, with label, formatter, and validation rules. This keeps the mapping in one place when the schema drifts and makes it easy to reuse the same map between export and import (round-trip: export → edit → re-import).
Model-aware imports. Resolve rows to models via an explicit unique key (not the primary key), apply updateOrCreate semantics you control, cast dates and booleans yourself, and normalise headers (trim, lowercase, snake_case) before matching — real spreadsheets arrive with stray spaces and inconsistent casing.
Test the round trip in CI. A small fixture workbook plus a feature test that runs import → assert counts → export → assert headers is cheap and catches most regressions, including the kind of heading/pluralisation bug fixed in v1.0.1.
^1.0.1 in composer.json to avoid the old behaviour on fresh installs.memory_limit, prefer chunked/queued exports, and be aware that PhpSpreadsheet-style writers hold the whole sheet in memory unless using a streaming writer.=, +, -, or @ on export; spreadsheets execute them. On import, never eval or trust formula cells.01/02/2024 is two different dates depending on who made the file. Force a date format in your mapping, or require ISO strings, and document it for users.QUEUE_CONNECTION=sync masks failures — exports appear instantly locally and silently break in production. Run a real worker (redis/database) locally at least once.composer.json constraints against your Filament version before upgrading either; action signature changes are the usual breakage point.How can I help you explore Laravel packages today?