A fluent, extensible datatable package for Laravel. Write ordinary Laravel query code — Eloquent models, query builders, collections, or plain arrays — and get automatic, header-driven searching, sorting, filtering, pagination, and response formatting for free.
use Syscage\Datatable\Facades\Syscage;
return Syscage::datatable(User::class)
->search(['name', 'email', 'roles.name'])
->sortable(['id', 'name', 'created_at'])
->filter(['status', 'country'])
->where('is_active', true)
->latest();No paginate(), no manual query parsing, no hand-rolled JSON shape. The request headers do the driving; the package does the rest.
Requires PHP 8.2+ and Laravel 12 or 13.
composer require syscage/laravel-datatableThe service provider and Syscage facade are auto-discovered — there is nothing else to register.
Publish the config file if you want to customize headers, defaults, or the response shape:
php artisan vendor:publish --tag=datatable-configThis publishes config/datatable.php.
Build a datatable from anything: a model class name, a model instance, an Eloquent builder, an Eloquent relation, a query builder, a collection, a lazy collection, or a plain array.
use Syscage\Datatable\Facades\Syscage;
// From a model class name
return Syscage::datatable(User::class);
// From an already-built Eloquent query
return Syscage::datatable(User::query()->where('status', 1));
// From a relation
return Syscage::datatable($company->users());
// From the query builder
return Syscage::datatable(DB::table('users'));
// From a collection
return Syscage::datatable(User::all());
// From a lazy collection
return Syscage::datatable(User::cursor());
// From a plain array
return Syscage::datatable($rows);Approve searchable, sortable, and filterable columns, then return the result directly from a controller action — it implements Illuminate\Contracts\Support\Responsable and renders as JSON automatically:
class UserController
{
public function index()
{
return Syscage::datatable(User::class)
->search(['name', 'email'])
->sortable(['id', 'name', 'email', 'created_at'])
->filter(['status', 'country'])
->resource(UserResource::class);
}
}Search keyword, page, rows per page, sort column/direction, and filters are all read automatically from request headers (X-SC-Datatable-Search, X-SC-Datatable-Rows, X-SC-Datatable-Page, X-SC-Datatable-Sort, X-SC-Datatable-Order, X-SC-Datatable-Filters) — pagination happens without ever calling paginate() yourself.
The response is returned as:
{
"datatable": {
"data": [],
"meta": {
"page": 1,
"rows": 10,
"total": 42,
"pages": 5,
"from": 1,
"to": 10,
"count": 10,
"has_next": true,
"has_prev": false,
"search": "",
"sort": null,
"order": "asc",
"execution_ms": 4.32
}
}
}For request headers, relationship search, filtering, custom callbacks, API resources, transform, append/only/hidden, response customization, method forwarding, macros, and advanced usage, see the full documentation:
https://doc.syscage.com/laravel-datatable
The MIT License (MIT). See LICENSE.md for more information.