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

Import Export Laravel Package

moonshine/import-export

Import/export companion for MoonShine admin panels: add CSV and Excel import/export actions to Laravel resources, map columns, validate rows, and handle large files in background queues with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Confirm your runtime before requiring the package. As of 2.1.0 the package requires PHP 8.3+ — PHP 8.2 was dropped as a hard breaking change, and PHP 8.5 is now supported. Check your app's composer.json require.php constraint, your local/Herd binary, and your CI matrix (including any shivammathur/setup-php pins) before bumping:

    php -v
    composer require moonshine/import-export:^2.1
    

    If you're still on 8.2, either upgrade PHP first or stay pinned to the last 2.0.x release; Composer will refuse to install 2.1.0 on an 8.2 platform.

  2. Require the package alongside MoonShine v3 (the package targets the v3 handler pipeline — confirm the exact MoonShine and PHP constraints in its composer.json before installing):

    composer require moonshine/import-export
    

    Service provider should auto-register; no publish step is usually required, but check the README for any config/vendor:publish tag.

  3. Read the source first, not the README. With a small, single-maintainer package, the README lags the code. Start at src/ and look for the handler classes (typically ImportHandler / ExportHandler extending MoonShine's Handler/ResourceHandler base). Those constructors tell you the real API — field list, disk, filename, format.

  4. First use case — export a resource from the admin UI. Register the export handler on the resource:

    // app/MoonShine/Resources/UserResource.php
    public function handlers(): array
    {
        return [
            ...parent::handlers(),
            new ExportHandler(),
        ];
    }
    

    You should now see an export action on the resource index. Verify it produces a file on the configured disk before you customize anything.

  5. Then do the import path symmetrically — add ImportHandler to the same resource and upload a CSV exported in step 3. Round-tripping your own export is the fastest smoke test that column mapping, types, and encodings line up.

Implementation Patterns

Per-resource, declarative handlers. The dominant pattern is registering handlers on a MoonShineResource, which gives you an admin-facing button with no extra controller code. Keep import and export handlers on the same resource so the column schema lives in one place.

Column/field mapping. Most likely the handler takes an array of field identifiers (or Field instances). Define one mapping used by both import and export so the formats never drift:

$fields = ['id', 'name', 'email', 'created_at'];
new ExportHandler(fields: $fields, disk: 'local', filename: 'users.xlsx');
new ImportHandler(fields: $fields, disk: 'local');

Custom value resolution for relationships / computed columns. For belongs-to relations you’ll typically need a closure or column alias that resolves the relation to a scalar on export and back to a foreign key on import (email → user_id). If the package exposes callbacks, wire them per-field; otherwise subclass the handler and override the row transform.

Round-trip as the contract. Treat the export output as the import schema. Add a header row, freeze column order, and pin date formats. This lets support staff export, edit in Excel, re-import — the single most common day-to-day workflow for admin panels.

Job-backed for large datasets. Do not run imports on the HTTP request once you cross a few thousand rows. Wrap the import in a queued job that instantiates the same handler and points at the uploaded file path on disk, so the logic stays in one place and only the transport moves to the queue.

Cross-resource handler reuse. Because a handler is just a class, instantiate it with different field arrays on different resources (e.g. a shared ExportHandler for users, orders, invoices) rather than writing per-resource subclasses unless you need custom transforms.

Integrate with MoonShine notifications. After import, surface success/failure counts through MoonShine’s MoonShine::notification() / flash layer so admins get row-level feedback instead of a silent redirect.

Gotchas and Tips

  • PHP 8.3 is now the floor. 2.1.0 dropped PHP 8.2 support outright — this is flagged as a breaking change in the release notes, so treat it as a major-equivalent bump for deployment purposes. Align every environment: local Docker/Herd images, staging/production runtimes, GitHub Actions matrices, and any config.platform.php override in composer.json (a stale platform pin will happily install 2.1.0 into an app that actually runs 8.2 and then fatal at runtime).
  • PHP 8.5 is supported, but verify your other deps. The package declaring 8.5 support doesn't mean MoonShine v3, your queue driver, or your spreadsheet library do. If you're moving to 8.5, upgrade the whole stack in one PR and run the round-trip smoke test from Getting Started before trusting it in production.
  • Memory and timeouts on Excel, not CSV. CSV streams; spreadsheets usually don’t. For imports above ~5k rows prefer CSV or chunk the reader. Raise max_execution_time / memory_limit in the job, not the web request.
  • Transaction safety. Wrap imports in DB::transaction only if the file is small; for large files use chunked inserts with per-chunk validation and collect failed rows, otherwise one bad cell rolls back thousands of good ones.
  • Validation is on you. Assume the package does not run per-row validation against your model rules. Validate headers against your field array up front (fail fast on a missing column) and validate rows before persisting — a silently shifted column is the classic import bug.
  • Header/encoding mismatches. Excel-saved CSVs are UTF-8 with BOM; strip the BOM and normalize line endings or the first column name won’t match. Watch delimiter detection for locales that use ;.
  • Date and decimal coercion. Excel turns 2025-12-29 into a serial number and strips leading zeros from IDs and phone numbers. Either force text columns in the export or parse defensively on import.
  • File lifecycle. Delete the uploaded file in a finally block after import and put a TTL/cleanup on exported files; admin disks fill up quickly if exports are left behind.
  • Disk configuration. Exports go through Laravel’s filesystem — make sure the configured disk is visible to the web (or served through a download route), and that queued jobs and the web process resolve the same disk. A local disk that isn’t the public one is the usual “export produced nothing” cause.
  • Handler ordering. MoonShine runs handlers in the order returned by handlers(); append with ...parent::handlers() so you don’t silently disable authorization or other resource handlers.
  • Version pinning and upgrade cadence. Pin a minor ("moonshine/import-export": "^2.1") and read the changelog on every bump — the maintainer ships requirement-level breaking changes (as 2.1.0 did for PHP) without a major version bump. Skim internal handler signatures too: those are the likeliest thing to break on a MoonShine major upgrade.
  • Debugging empty exports. Log the resolved field array and row count inside the handler before the file write; most “empty file” reports trace to a resource query scope or policy filtering rows to zero, not the handler itself.
  • Extension points. If the handler classes are non-final, subclass and override the row-read/write or getFields() method rather than forking the package — it keeps you on upstream bug fixes and makes the next PHP-version bump someone else's problem.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums