ArticleLaravel5 min read

From Project-Based Datatable to Laravel Composer Package

How I turned my Laravel Inertia Datatable project implementation into a reusable Composer package for server-side search, filters, sorting, relations, and pagination.

raprmdn
Rafi Putra Ramadhan
Laravel
PHP
Composer
Eloquent
Datatable
From Project-Based Datatable to Laravel Composer Package

From Project-Based Datatable to Laravel Composer Package

I recently created a standalone Laravel Composer package called raprmdn/laravel-inertia-datatables.

This package started from my older project-based implementation: laravel-inertia-datatable.

The original version was built as a complete Laravel, Inertia, React, Tailwind, and shadcn/ui project. It worked as a full implementation, but the backend datatable logic was reusable enough that it should not stay locked inside one project.

So I extracted the core logic into a Composer package.

Package: Packagist

Source Code: GitHub

The Problem

Datatable logic is repeated in many Laravel applications.

Most admin panels and internal tools need similar features:

  • Search
  • Filters
  • Date range filters
  • Sorting
  • Pagination
  • Relationship columns
  • Configurable limits

At first, this logic usually lives directly inside controllers. But after building multiple tables, the same patterns keep repeating.

That was the main reason I wanted to create a package.

Why I Extracted It

The original repository was useful as a project example, but it was not flexible enough to reuse in other applications.

If I wanted the same datatable behavior in another Laravel project, I would need to copy the code manually.

That creates a few problems:

  • Duplicate logic
  • Harder maintenance
  • Inconsistent implementation between projects
  • More controller code than necessary

By moving the datatable logic into a package, I can reuse the same backend behavior across different Laravel applications.

Why Backend First?

Even though the package name includes Inertia, the current version is backend-first.

It can be used with:

  • Inertia
  • API resources
  • Blade
  • JSON responses
  • Custom Laravel responses

The frontend components are planned for a future release, but the most important part is the backend query behavior.

The backend is where search, filters, sorting, relations, and pagination need to be handled safely and consistently.

Basic Usage

Install the package using Composer:

Terminal
composer require raprmdn/laravel-inertia-datatables

Publish the configuration file:

Terminal
php artisan vendor:publish --tag=inertia-datatables-config

Then use the DataTable facade:

Controller.php
use App\Models\User;
use Raprmdn\DataTables\Facades\DataTable;
 
$users = DataTable::query(User::query())
    ->searchable(['name', 'email'])
    ->orderBy('created_at', 'desc')
    ->make();

Filters and Sorting

The package supports safe filter and sort mappings.

Controller.php
use Raprmdn\DataTables\Facades\DataTable;
 
$filterColumns = [
    'status'   => 'status',
    'priority' => 'priority.name',
];
 
[$columnFilters, $dateRanges] = DataTable::parseFilters(
    $request->query('filters', []),
    $filterColumns
);
 
$sortColumns = [
    'name'       => 'name',
    'email'      => 'email',
    'created_at' => 'created_at',
];
 
[$sort, $allowedSorts] = DataTable::parseSort(
    $request->query('col'),
    $sortColumns
);
 
$users = DataTable::query(User::query())
    ->searchable(['name', 'email'])
    ->applyFilters($columnFilters)
    ->allowedFilters(array_values($filterColumns))
    ->applySort($sort)
    ->allowedSorts($allowedSorts)
    ->orderBy('created_at', 'desc')
    ->make();

This keeps request parameters simple while still letting the backend control which columns are allowed.

Relationship Support

The package also supports relationship columns using dot notation.

Controller.php
DataTable::query($query)
    ->with(['contact.channel', 'priority'])
    ->searchable([
        'number',
        'contact.name',
        'contact.email',
        'contact.phone',
    ])
    ->make();

For example:

'contact.name'

means:

  • contact is the relationship method on the model
  • name is the column on the related table

This is useful for admin panels where table data often comes from multiple related models.

What Changed From the Old Project?

The old repository was a full project implementation. The new package is focused on reusable backend logic.

Some important changes:

  • Moved the datatable logic into a Composer package
  • Added the Raprmdn\DataTables namespace
  • Added Laravel auto-discovery support
  • Added a service provider
  • Added a facade API
  • Added publishable configuration
  • Added filter and sort parser helpers
  • Separated backend logic from frontend components

The old project answers:

How does this datatable work in one Laravel Inertia app?

The new package answers:

How can this datatable logic be reused across Laravel apps?

Current Limitations

The package is still in beta.

Current limitations:

  • The public API may still change before v1.0.0
  • Frontend starter components are not included yet
  • Advanced filter operators are not implemented yet
  • Relation sorting does not support every relation type
  • Automated tests are still planned

Roadmap

Next improvements I want to work on:

  • Add automated tests
  • Improve documentation
  • Add more filter operators
  • Add optional Inertia React starter components
  • Add a column definitions API

Final Thoughts

This package is still early, but it already solves the main problem I wanted to fix: reducing repeated datatable query logic in Laravel controllers.

The original project will remain as the project-based implementation and will be updated to use the standalone Composer package in a future release.

Building the feature inside a real project first helped me understand the problem better. After that, extracting it into a package felt much clearer.

Links: