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

Laravel Datatables Export Laravel Package

yajra/laravel-datatables-export

Laravel DataTables Export is a plugin for yajra/laravel-datatables that enables server-side exports via queues and OpenSpout, with optional Livewire and DataTables button integrations. Requires PHP 8.3+ and Laravel 13. Install via Composer, run queue:batches-table and migrate, then publish assets fo...

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

This package is a narrow, additive plugin rather than infrastructure: it slots into an existing yajra/laravel-datatables service class via the WithExportQueue trait and converts what is normally a synchronous, request-bound spreadsheet download into a queued job with a pollable status endpoint. That is the correct shape for the problem it solves — large exports are the classic cause of PHP timeouts, memory exhaustion, and Nginx 504s, and offloading to a queue with OpenSpout's streaming writer removes both constraints.

It is a good fit only under a specific precondition: the application already uses Yajra DataTables for its listing screens. The package does not help non-DataTables tables, plain Eloquent exports, or report generation outside a DataTables context. Where that precondition holds, the marginal cost is a trait, a button config, and a migration — genuinely low. Where it does not, the cost is adopting the entire Yajra DataTables stack first, which is a much larger architectural decision.

Integration feasibility

Feasible and well-bounded. The surface area is small and explicit: one trait, one Blade/JS asset (non-Livewire) or one Livewire component, one published config, one migration (queue:batches-table), one scheduled purge command. It reuses the existing DataTable definition — column exportFormat() calls are added to columns that already exist — so export formatting lives next to column definition rather than in a parallel export class that drifts.

Two feasibility constraints need to be confirmed before committing:

  1. Version-line feature asymmetry. The package is version-locked to the host framework (Laravel 13 → package 13.x, 12 → 12.x). The features most teams want are recent and only in the 13.x line: non-Livewire queued buttons (13.3.0), configurable queue (13.2.0), row-level progress (13.3.0), OpenSpout 5 (13.1.0), QueryBuilder support (12.2.0). A team on Laravel 11 or 12 will get a materially weaker product than the README implies. This is the single biggest planning trap.
  2. Queue batch support. Progress tracking depends on database-backed job batches, meaning a job_batches table and a queue driver that respects Bus::batch. Applications on SQS or a mixed-driver setup need to validate this explicitly; it is not a "just works" dependency.

Technical risk

  • Adoption risk (low-to-moderate). 36 stars and 0 dependents is thin for a production dependency. The mitigating factor is that it is maintained under the Yajra umbrella alongside the parent DataTables package, so it is not a random solo repo — but it is still effectively single-maintainer, and a Laravel major bump forces a coordinated upgrade of the whole Yajra set.
  • Authorization risk (high, and the one I would gate on). Exports bypass pagination and re-execute the DataTable query with client-supplied search, ordering, and filter parameters. Any tenancy or row-level authorization that lives in the column renderer, a resource transformer, or the view layer will be silently absent from the export. The blast radius is a full-table data exfiltration through a legitimate button.
  • Access-token risk (moderate). Status and download URLs use encrypted tokens with a 1,440-minute default TTL. These are bearer credentials: they land in browser history, proxy logs, Referer headers, and any support ticket where a user pastes a broken link. Token TTL and file retention must be deliberately aligned — weekly purge with a 24-hour token is coherent; the reverse leaves live download links for deleted files.
  • Spreadsheet injection risk (moderate). Any cell containing user-controlled text beginning with =, +, -, or @ can execute as a formula when opened in Excel. The package documents forcing numeric columns to text (exportFormat('@')) but does not document formula neutralization. Assume it is the integrating team's responsibility and budget for it.
  • Supply-chain risk (low, but note the signal). A 13.2.2 patch release exists specifically to require a patched PhpSpreadsheet, and 12.1.1 changed to unescaped output. Both are reminders that this package sits on top of a large dependency tree that has had real vulnerabilities.
  • emailTo risk (moderate). The option to email a completed export implies outbound mail and a recipient parameter. Confirm whether that value is server-controlled or client-supplied before enabling it — a client-supplied recipient is a data-loss channel.

Key questions

  • Which Laravel line are we on, and does the corresponding package line actually expose the button/progress/queue features we are promising users?
  • Does our DataTable query enforce tenant and role scoping in the query builder itself, or downstream of it?
  • Which disk do exported files land on, what is its retention policy, and does it match token_ttl?
  • Is job_batches present in production, and does our queue driver support batch progress reliably?
  • Do we need the jQuery/DataTables Buttons path or the Livewire path — and therefore which of the two front-end dependencies are we taking on?
  • Is there a test suite covering the export job and the download authorization, not just the happy-path button?
  • Who owns the scheduled datatables:purge-export and its alerting?

Integration Approach

Stack fit

Requires Laravel 13, PHP 8.3+ (OpenSpout 5.x pushes toward 8.4+), yajra/laravel-datatables-buttons ^13.0, and jQuery DataTables 2.x on the front end. Livewire is optional but is the cleaner path if the application is already Livewire-based — it avoids publishing and versioning a jQuery plugin asset. If the app is Livewire/Alpine without jQuery, the non-Livewire button (added only in 13.3.0) is not a free option; it drags in DataTables Buttons and its asset pipeline.

Migration path

No data migration. The one schema change is php artisan queue:batches-table && php artisan migrate, which is additive and safe. Runtime steps: composer require yajra/laravel-datatables-export:"^13.0", publish config and assets under the datatables-export tag, add WithExportQueue to the target DataTable, add the export button or <livewire:export-button> to the view, and ensure a queue worker is running. Rollback is clean: remove the button and the trait; the batches table and published assets are inert.

Compatibility

Pin the package major to the framework major. Explicitly record in the upgrade runbook that Laravel major upgrades now require a simultaneous bump of laravel-datatables, -buttons, -export, and possibly OpenSpout — that is a four-package coordination point, not a routine composer update. Verify the PHP floor (8.3 vs 8.4) against the OpenSpout resolution in composer.lock before promoting to production; the 13.1.0 release exists precisely because this got tangled.

Sequencing

  1. Spike (1–2 days). One DataTable, the smallest one, end-to-end on staging: trait, button, worker, poll, download. Confirm the version line actually has the features in scope.
  2. Authorization review (gate). Prove that an export performed by a low-privilege user returns only rows that user could see in the paginated table. Add an automated test for this before any further rollout.
  3. Storage and lifecycle. Decide the disk, the retention window, token_ttl, and the schedule for datatables:purge-export. Wire ExportStarted / ExportCompleted / ExportFailed to logging and metrics.
  4. Roll out by table. Enable per DataTable in priority order; the largest, most filtered tables first (they benefit most), the smallest last.
  5. Optional email path. Enable emailTo only after confirming recipient values are server-controlled.

Operational Impact

Maintenance

Steady-state burden is low but non-zero and concentrated at framework upgrade time. The package tracks Laravel majors closely (13.x shipped for Laravel 13, 12.3.0 added Livewire 4), so staying current means upgrading on the framework's cadence, not the package's. The published config and JS asset are forkable code in the repo — if we customize either, we own merge conflicts on every bump. Budget a recurring small line item rather than a one-time integration.

Support

Support load comes almost entirely from users, not from the library. Export buttons invite questions about missing columns, wrong date formats, and "the download is blank" — all of which map to exportFormat() misconfiguration. Publishing an internal one-pager on formatting ('00000000000' for leading zeroes, '@' to force text, NumberFormat::FORMAT_DATE_* for dates) will absorb most of it. The single-maintainer upstream reality means we should not plan on vendor SLAs; treat it as community-supported and keep the integration thin enough to fork or replace if abandoned.

Scaling

Exports scale with queue capacity, not web capacity — that is the whole point, and it is a genuine win. OpenSpout streams rows, so memory per job is bounded by the writer's buffer rather than dataset size. The real scaling limits are elsewhere: concurrent export jobs compete with application jobs on the same workers, and a handful of large exports can starve transactional jobs. Once enabled on multiple tables, give exports a dedicated queue (configurable since 13.2.0) with its own worker pool and a bounded concurrency, plus per-user rate limiting so one user cannot enqueue ten large exports. Also watch database load — an unthrottled export runs the same query shape as the listing but without the LIMIT, so chunk the job and index for the filter combinations users actually export.

Failure modes

  • Job failure / worker down. User sees the error state (errorText) or an indefinitely pending progress bar. ExportFailed and the JS datatables-export:error event are the hooks — wire them to alerting so failures are not discovered by users.
  • Silent success with wrong data. The authorization failure mode described above. This is the one that does not announce itself; only a test catches it.
  • Expired token. User bookmarks or shares a status URL past token_ttl and gets a dead link with no explanation. Acceptable if the download window is communicated in the UX.
  • Purged file, live link. Purge schedule outrunning retention intent — align the two explicitly.
  • Disk exhaustion. Repeated large exports without purge. The weekly purge command is the mitigation; it must be actually scheduled and monitored, not documented and forgotten.
  • Batch table absent or driver unsupported. Progress polling silently degrades. Detectable in the spike.

Ramp-up

Estimate 1–3 days for a developer already fluent in Yajra DataTables to ship the first table to staging, and roughly one sprint to harden: authorization test, storage lifecycle, queue isolation, observability, and the internal formatting guide. The learning curve is not the package — it is DataTables' server-side parameter contract, which the team likely already knows. Ramp-up is genuinely low for DataTables shops and materially higher (a week or more) for teams adopting Yajra DataTables as a side effect of wanting exports.

Recommendation

Adopt conditionally: proceed only if we are already on yajra/laravel-datatables and on Laravel 13, and only after the export authorization review passes. On Laravel 11/12, defer or scope down — the 12.x line lacks the queued non-Livewire button and configurable queue, which are the features that justify the dependency. If neither precondition holds, a bespoke Bus::batch job with OpenSpout is a few hundred lines and avoids a fourth package in the upgrade chain.

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.
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode