Why Use Server-Side Processing in DataTables?

             

When displaying tabular data on a website, especially in admin panels, dashboards, or reports built with CodeIgniter 4, jQuery DataTables is a go-to solution for its powerful features like pagination, searching, and sorting. However, the default client-side processing mode loads the entire dataset into the browser at once. This works fine for small tables (under 10,000 rows), but it quickly becomes problematic with larger datasets.

That's where server-side processing shines. Instead of sending all records to the client upfront, DataTables makes an AJAX request to your server (in this case, your CodeIgniter 4 controller) for each user action—such as changing pages, searching, or sorting. The server handles the heavy lifting: querying the database, applying filters, ordering results, and returning only the visible page (e.g., 10-50 rows). This approach dramatically improves performance and user experience.

Here are the key benefits of using server-side processing in DataTables:

  • Lightning-fast loading: No need to wait for thousands or millions of rows to download initially.
  • Scalability: Easily handle 100,000+ records without browser slowdowns, memory issues, or crashes.
  • Security & efficiency: Only requested data is transmitted, reducing bandwidth and keeping sensitive information server-side.
  • Better SEO & accessibility: Faster page loads improve Core Web Vitals and user retention.
  • Real-time data: Perfect for dynamic datasets that change frequently (e.g., live logs or e-commerce orders).

In contrast, client-side processing relies on JavaScript to handle everything in the browser, which can lead to sluggish performance on mobile devices or older hardware. By switching to server-side processing in CodeIgniter 4, you leverage the power of PHP and MySQL for optimized queries, ensuring your application remains responsive even as your data grows.



Server-Side DataTables in CodeIgniter 4: Complete AJAX Tutorial

Table Of Content

1 Prerequisites

  • PHP ≥ 8.1
  • Composer
  • MySQL database
  • Basic knowledge of CodeIgniter 4 (Models, Controllers, Views, Migrations)

2 Introduction

In this CodeIgniter 4 tutorial, you'll build a fully functional user list with server-side pagination, searching, and ordering using jQuery DataTables, MySQL, Bootstrap 5, and the MVC structure.

In this tutorial, we'll implement server-side processing step-by-step using AJAX and the MVC structure—making it easy to scale your tables for real-world applications.

3 Create a New CodeIgniter 4 Project

3.1 Install Codeigniter 4 Project

First, make sure your computer has a composer.
Use the following command to install new Codeigniter Project.

composer create-project codeigniter4/appstarter ci4-datatables

Then, navigate to your project directory:

cd ci4-datatables

3.2 Configure Environment and MySql Database

Rename the env file to .env and set the development mode in the .env file also configure mysql:

# CI_ENVIRONMENT = production
CI_ENVIRONMENT = development


DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ci4_datatable
DB_USERNAME=root
DB_PASSWORD=

Create the database ci4_datatable.

4 Install Required Assets (via CDN)

We'll use Bootstrap 5 and DataTables CDN for simplicity.

Download DataTables by either directly downloading the files or using a package manager like npm or CDN.


Using CDN:

In your view file, add the following lines to include the DataTables library:


<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.1/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/1.11.4/css/dataTables.bootstrap5.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.22/js/dataTables.bootstrap5.min.js"></script>

5 Create New Controller: UserController

Create a controller to handle data requests using the following command:

php spark make:controller UserController

In app/Controllers/UserController.php:

<?php
namespace App\Controllers;

use App\Models\UserModel;
use CodeIgniter\HTTP\RequestInterface;

class UserController extends BaseController
{
    public function index()
    {
        return view('users');
    }

    public function getUsers()
    {
        $request = service('request');
        $model = new UserModel();

        $draw        = $request->getPost('draw');
        $start       = $request->getPost('start');
        $length      = $request->getPost('length');
        $searchValue = $request->getPost('search')['value'];

        $orderColumnIndex = $request->getPost('order')[0]['column'] ?? 0;
        $orderDir         = $request->getPost('order')[0]['dir'] ?? 'asc';
        $columns          = $request->getPost('columns');
        $orderColumn      = $columns[$orderColumnIndex]['data'] ?? 'id';

        // Total records
        $totalRecords = $model->countAll();

        // Filtered query
        $builder = $model->builder();
        if (!empty($searchValue)) {
            $builder->like('name', $searchValue)
                    ->orLike('email', $searchValue);
        }

        $totalFiltered = $builder->countAllResults(false); // Count without limit

        // Ordering & Pagination
        $builder->orderBy($orderColumn, $orderDir);
        $data = $builder->limit($length, $start)->get()->getResultArray();

        $jsonData = [
            'draw'            => intval($draw),
            'recordsTotal'    => intval($totalRecords),
            'recordsFiltered' => intval($totalFiltered),
            'data'            => $data
        ];

        return $this->response->setJSON($jsonData);
    }
}
?>

6 Create Migration and Model

Create a migration file to define the table structure:

php spark make:migration AddUser

Edit the migration file to define the table structure:

<?php
namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class AddUser extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id' => ['type' => 'BIGINT', 'unsigned' => true, 'auto_increment' => true],
            'name' => ['type' => 'VARCHAR', 'constraint' => 255],
            'email' => ['type' => 'LONGTEXT'],
            'created_at' => ['type' => 'TIMESTAMP', 'null' => true],
            'updated_at' => ['type' => 'TIMESTAMP', 'null' => true],
        ]);
        $this->forge->addKey('id', true);
        $this->forge->createTable('users');
    }

    public function down()
    {
        $this->forge->dropTable('users');
    }
}


Run the migration:

php spark migrate


php spark make:model UserModel

Configure the UserModel:

<?php
namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    protected $table = 'users';
    protected $primaryKey = 'id';
    protected $allowedFields = ['name', 'email', 'created_at', 'updated_at'];
}

7 Create Database Seeder

For seeding the test data, create a seeder class:

php spark make:seeder UserSeeder

In app/Database/Seeds/UserSeeder.php:

<?php
namespace App\Database\Seeds;

use CodeIgniter\Database\Seeder;
use CodeIgniter\I18n\Time;
use App\Models\UserModel;
class UserSeeder extends Seeder
{
   public function run()
{
    $faker = \Faker\Factory::create();
    $model = new \App\Models\UserModel();

    for ($i = 0; $i < 100; $i++) {
        $model->insert([
            'name'       => $faker->name,
            'email'      => $faker->unique()->safeEmail,
            'created_at' => \CodeIgniter\I18n\Time::now(),
            'updated_at' => \CodeIgniter\I18n\Time::now(),
        ]);
    }
}
}

Run the seeder:

php spark db:seed UserSeeder

8 Create the View with DataTables

Create a view file users.php in the app/Views directory to display the DataTable:

  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Users - Server-Side DataTables</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.datatables.net/2.0.0/css/dataTables.bootstrap5.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
    <script src="https://cdn.datatables.net/2.0.0/js/dataTables.min.js"></script>
    <script src="https://cdn.datatables.net/2.0.0/js/dataTables.bootstrap5.min.js"></script>
</head>
<body class="container mt-5">
    <h1>Users List (Server-Side Processing)</h1>
    <table id="userTable" class="table table-striped table-bordered">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Email</th>
                <th>Created At</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>

    <script>
    $(document).ready(function() {
        $('#userTable').DataTable({
            processing: true,
            serverSide: true,
            ajax: {
                url: '<?= base_url('usercontroller/getusers') ?>',
                type: 'POST'
            },
            columns: [
                { data: 'id' },
                { data: 'name' },
                { data: 'email' },
                { data: 'created_at' }
            ]
        });
    });
    </script>
</body>
</html>

9 Define a Route

In app/Config/Routes.php, define routes for the controller:

use CodeIgniter\Router\RouteCollection;
/**
 * @var RouteCollection $routes
 */
$routes->get('/', 'Home::index');
$routes->get('users', 'UserController::index');
$routes->post('usercontroller/getusers', 'UserController::getUsers');

10 Folder Structure

Ensure the folder structure is correctly set up with controllers, views, and routes to maintain the app's organization.

11 Run Web Server to Test the App

Finally, run your development server to test server-side DataTables in CodeIgniter 4 functionality:

php spark serve

Visit: http://localhost:8080/users

You should see a searchable, paginated, sortable table loading data via AJAX.

12 Conclusion

You've now implemented server-side DataTables in CodeIgniter 4 successfully! For larger projects:
  • Use libraries like Hermawan\DataTables or irsyadulibad/ci4-datatables → one-liner JSON output.
  • Add CSRF protection for POST requests.
  • Implement column-specific search.
  • Add action buttons (edit/delete) with proper security.
This approach scales well for admin panels, reports, and dashboards.
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

You need PHP 8.1 or higher, Composer, MySQL database, and a fresh CodeIgniter 4 installation configured in .env.

Create a 'users' table migration with columns: id (BIGINT unsigned auto_increment primary key), name (VARCHAR 255), email (LONGTEXT), created_at and updated_at (TIMESTAMP nullable). Run migration and seed fake data.

jQuery, Bootstrap 5 CSS/JS, DataTables core, and DataTables Bootstrap 5 integration (jquery.dataTables.min.js and dataTables.bootstrap5.min.js).

In getUsers(), retrieve POST parameters (draw, start, length, search[value], order). Calculate total/filtered records, apply global search with like/orLike on name and email, order dynamically, limit/offset results, and return JSON with draw, recordsTotal

Yes, global search on name and email columns using LIKE/OR LIKE. Ordering is dynamic based on column index and direction from DataTables.

Pagination uses 'start' (offset) and 'length' (limit) from POST data. The model fetches limited results with findAll($limit, $start) after applying search and order.

Common issues: Incorrect AJAX URL or route, database connection errors in .env, missing POST type in ajax, case-sensitive controller name, or no seeded data. Check browser console/network tab for errors.

No, only global search is implemented. For individual column search, add more POST parameters and extend the query builder.

Add columns in DataTables init and nest action buttons in the data loop (e.g., $nestedData['action'] = ''). Render as HTML in the table.

In the view JavaScript: $('#userTable').DataTable({ processing: true, serverSide: true, ajax: { url: base_url('usercontroller/getusers'), type: 'POST' }, columns: [{data:'id'}, {data:'name'}, {data:'email'}, {data:'created_at'}] });