amjadiqbal/filament-xlsx-import
A Filament plugin for importing XLSX spreadsheets directly into your resources, with a simple upload flow and column mapping so you can bring spreadsheet data into your admin panel without writing custom import logic.
openspout, not a bespoke parsing engine, so you are buying wiring and validation ergonomics, not proprietary technology.sheet('X'), headerOffset(), and acceptCsv() toggles map directly to product requirements you would otherwise argue about in refinement: "only import from the 'Data' tab", "our exports have two title rows before the header", "customers export as CSV from Excel and we don't want to support .xls". Each is a config flag rather than a story.ImportDispatcher constructs every chunk's job in that initial request, so request memory grows with row count — is a product constraint, not just an implementation note. It tells you this package is right for bounded, human-scale uploads (thousands to low tens of thousands of rows) and that "import a 500k-row customer list" is a separate initiative requiring queueing, chunked upload, or an out-of-band job pipeline.openspout (4.23) verified, plus a fresh composer require on clean apps and a headless-Chrome UI test. That is enough to slot into a framework-upgrade plan without budgeting a migration spike, and it de-risks the "we'll upgrade Laravel next quarter" conversation.sheet('X') fix means a misconfigured or unexpected workbook produces a message an admin can act on ("The workbook has no sheet called "X"") rather than a dead-end "could not be read as a spreadsheet". The acceptCsv(false) fix means the file picker stops silently rejecting .xls before the guidance about saving as .xlsx can be shown — i.e. users get told what to do instead of being blocked without explanation. Both reduce support tickets, which is a measurable PM concern.Adopt it when:
composer update amjadiqbal/filament-xlsx-import, no API changes in 1.0.1), but the package is at 1.0.x with a maintainer-driven test matrix rather than a large ecosystem.Look elsewhere (or build) when:
openspout or Laravel Excel directly).openspout) fits your audit posture..xls input as a first-class format rather than an error message telling users to re-save as .xlsx.For executives: We need bulk data entry in the admin panel for [onboarding / catalogue refresh / migrations]. This is an off-the-shelf Laravel/Filament package that covers the whole "upload a spreadsheet, pick a sheet, map columns, import" flow, tested across our current PHP, Laravel, and Filament versions. It replaces a custom build estimated at [X days] with a dependency we can adopt this sprint. The 1.0.1 patch is a stabilisation release — better error messages when a file is missing an expected sheet, a fix so users who upload .xls are told to save as .xlsx instead of being silently blocked, and clearer documentation of how large files are handled. No API changes; upgrade is a one-line Composer update.
For engineering: It is a thin, honest wrapper over openspout with Filament form/action wiring. Version 1.0.1 is a code-review-driven patch: no API changes, composer update only. Two behavioural fixes (sheet-not-found message; acceptCsv(false) no longer pre-rejecting .xls) and a README correction. The important engineering fact, now documented rather than discovered in production: data rows are streamed once at import start, but core's ImportDispatcher builds every chunk's job in that first request, so request memory scales with row count — same as the CSV path. Column mapping re-reads only the sheet list and header rows. headerOffset() counts empty rows, so headerOffset(2) reads row 3. Verified on PHP 8.2–8.5 × Laravel 12/13 × Filament 4/5, against the lowest supported openspout (4.23), with a fresh Composer install and a headless-Chrome UI test. Practical implication: size-gate uploads or move large imports to a queued upload path before we promise big-file support.
Recommendation: Adopt for the admin import workflows in scope, pin the version, and file the large-file/queueing work as a separate backlog item rather than treating it as a gap in this package.
How can I help you explore Laravel packages today?