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...
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:
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
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.=, +, -, 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.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
token_ttl?job_batches present in production, and does our queue driver support batch progress reliably?datatables:purge-export and its alerting?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
token_ttl, and the schedule for datatables:purge-export. Wire ExportStarted / ExportCompleted / ExportFailed to logging and metrics.emailTo only after confirming recipient values are server-controlled.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
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.token_ttl and gets a dead link with no explanation. Acceptable if the download window is communicated in the UX.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.
How can I help you explore Laravel packages today?