sparclex/nova-import-card
sparclex/nova-import-card adds an import card to Laravel Nova. Upload CSV or Excel files, map columns to model fields, and import records straight from your dashboard—no custom code needed. Lightweight, configurable, and easy to add to any Nova resource.
Because the package is archived and its README is sparse, treat the source as the primary documentation: after installing, open vendor/sparclex/nova-import-card/src/ and read the card class, its service provider, and any published config/views before writing your own integration.
composer require sparclex/nova-import-card
app/Providers/NovaServiceProvider.php, either add the card to cards() for the dashboard or to a resource's cards() method so the import UI appears next to that resource. Prefer the resource-level placement — an import card only makes sense in the context of the model being imported.columns()/field-mapping method). This subclass is the extension point — you almost never use the package card directly.php artisan vendor:publish --provider="Sparclex\NovaImportCard\..." — confirm the exact provider name from the source). Published views are where you adjust the upload form and result messaging.rules() and persisted via Model::create() or an updateOrCreate() keyed on a unique column.Get one happy-path CSV import working end to end on a staging environment before touching custom column mapping or validation — the debugging loop is slow otherwise.
Subclass-per-import. The cleanest day-to-day pattern is one card subclass per importable model:
class ImportContactsCard extends ImportCard
{
public function __construct()
{
parent::__construct();
$this->model = \App\Models\Contact::class;
}
public function columns(): array
{
return ['name', 'email', 'company'];
}
}
Register it in the resource:
public function cards(Request $request)
{
return [new ImportContactsCard()];
}
Header-mapping instead of positional columns. If the package keys off columns() by order, insist on CSVs with a header row and validate headers against columns() before processing a single data row. This turns a silent "column B now means email" corruption into an upfront error — the most common real-world failure with any import card.
Validation as a pre-flight, not an afterthought. Run Validator::make($row, $rules) per row and collect failures into an array surfaced in the card response rather than aborting on the first bad row. A useful workflow is: upload → dry-run report (N valid, M invalid with row numbers) → confirm → persist. If the package only supports a single pass, wrap persistence in a transaction and roll back entirely on any validation failure so partial imports never land.
Chunked persistence. For imports beyond a few hundred rows, avoid loading everything into memory and inserting one-by-one inside the request. Use array_chunk + Model::insert() (skipping model events) or LazyCollection on the parsed file, and queue longer jobs. Note that the card was written pre-ShouldQueue-by-default era, so queueing is something you add around it.
Idempotent re-imports. Key on a natural unique column with updateOrCreate() so re-uploading a corrected file doesn't create duplicates. Decide explicitly which columns are "insert-only" (e.g. created_at) versus updatable.
Dry-run toggle in a custom view. A single checkbox in the published view that renders the parsed preview without persisting is cheap to add and pays for itself the first time a client uploads the wrong file.
component/boot/meta contract still matches your Nova version — Nova's card API changed materially after 2.x. On modern Nova, plan to fork and port rather than require and hope.columns() and reject the file otherwise.max_execution_time, PHP upload limits (upload_max_filesize, post_max_size), and Nova's own middleware before blaming the package.meta()/constructor output in a Vue devtools inspection of the card payload to see what the front end receives; that's faster than guessing.Model::create() directly. Route persistence through a small Importer service so you can unit-test parsing and validation without booting Nova, and so swapping the package out later (likely) doesn't touch business logic.columns(), model, and constructor meta to be your only real hooks; anything more means forking src/. Given the package's age, forking is often the more honest choice — budget for it rather than fighting the abstraction.How can I help you explore Laravel packages today?