The Ultimate AG Grid PHP Example (Updated for 2025)

Integrating AG Grid with a Modern PHP Backend

If you’re looking for an updated AG Grid PHP example, you’ve likely discovered that most tutorials online are outdated. They still use mysql_* functions, ignore prepared statements, or fail to handle AG Grid’s full filtering, sorting, and pagination capabilities.

This guide provides a modern, production-ready integration between AG Grid (v31+) and PHP 8.2+ using:

By the end, you’ll have a fully functional, high-performance datagrid that sorts, filters, and paginates directly through SQL queries triggered by your PHP backend.


Conclusion

This updated AG Grid PHP example provides a fully functional, enterprise-ready data grid with server-side sorting, filtering, pagination, and CRUD operations. The backend uses modern PHP (8.1+) with PDO, and the frontend leverages AG Grid v31’s server-side row model for optimal performance even with thousands of rows.

Next steps: Integrate AG Grid Enterprise features like Excel export, charting, or master/detail views, and enhance PHP with input validation, logging, and rate limiting for production deployment.


File structure recap:

aggrid-php-example/
├── index.html
├── server.php
├── db.php
└── (optional) .env for credentials

Run with php -S localhost:8000 and open http://localhost:8000. Your AG Grid will communicate seamlessly with the PHP backend, handling all dynamic data operations in real time.

Integrating AG Grid with PHP is a powerful way to handle large datasets with a modern, high-performance UI. Because PHP is a server-side language and AG Grid is a client-side JavaScript library, the bridge between them is typically a RESTful API that handles data fetching and updates. The Modern Architecture

In an updated stack, you move away from rendering HTML tables on the server. Instead, PHP acts as the backend engine—using a framework like Laravel or a simple Slim app—to serve JSON. AG Grid sits on the frontend, consuming that JSON. This separation allows for "Server-Side Row Model" features, where the grid only loads the data visible to the user, making it capable of handling millions of rows without crashing the browser. Data Fetching and CRUD An effective implementation involves a few key steps:

The API Endpoint: A PHP script queries your database (like MySQL) and returns the result as json_encode($data).

The Grid Configuration: On the frontend, you define columnDefs and use the fetch() API to pull from your PHP endpoint.

Updates: By using AG Grid's onCellValueChanged event, you can send an asynchronous POST or PUT request back to a PHP script to save changes to the database instantly. Security and Performance

Modern examples prioritize prepared statements (PDO) in PHP to prevent SQL injection. Additionally, with the latest AG Grid updates, you can leverage Integrated Charts and Advanced Filtering, which requires passing complex filter objects from the grid to your PHP logic to dynamically build the SQL query.

This guide provides a modern implementation of AG Grid (version 35.x) using PHP 8.x as the backend. By 2026, standard practices for data grids have shifted toward using an API-first approach where PHP serves JSON to the client-side grid. 1. Front-End: Grid Setup

Modern AG Grid versions utilize createGrid rather than older constructor methods. This example uses the Client-Side Row Model for simplicity, which is ideal for datasets up to 100,000 rows.

Use code with caution. Copied to clipboard 2. Back-End: PHP API (api.php)

In 2026, PHP is primarily used as an API layer to handle database operations securely. This updated example uses PDO with prepared statements to prevent SQL injection.

PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); $action = $_GET['action'] ?? ''; if ($action === 'read') // Fetch data for the grid $stmt = $pdo->query("SELECT id, name, email, role FROM users"); echo json_encode($stmt->fetchAll()); if ($action === 'update') // Basic CRUD update example $data = json_decode(file_get_contents('php://input'), true); $stmt = $pdo->prepare("UPDATE users SET name = ?, email = ? WHERE id = ?"); $stmt->execute([$data['name'], $data['email'], $data['id']]); echo json_encode(['status' => 'success']); ?> Use code with caution. Copied to clipboard 3. Key 2026 Best Practices

Virtualization: AG Grid enables row and column virtualization by default to handle large data efficiently.

Server-Side Row Model (SSRM): For millions of rows, use rowModelType: 'serverSide' to lazy-load data in chunks.

Immutable Data: Enable immutableData: true and provide a getRowId function (using your database primary key) to optimize re-renders during updates.

Security: Always use POST/PUT for updates and ensure your PHP backend validates all incoming JSON data. AG Grid What's new

Assuming you want a concise, up-to-date PHP example showing how to load data into AG Grid (frontend) and serve it from PHP (backend) via JSON — here’s a minimal end-to-end snippet.

Frontend (index.html)

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>AG Grid PHP Example</title>
    <script src="https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css" />
    <link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-theme-alpine.css" />
    <style>
      html, body, #myGrid  height: 100%; margin: 0; width: 100%; 
    </style>
  </head>
  <body>
    <div id="myGrid" class="ag-theme-alpine"></div>
<script>
      const columnDefs = [
         field: "id", sortable: true, filter: true, width: 90 ,
         field: "name", sortable: true, filter: true ,
         field: "email", sortable: true, filter: true ,
         field: "created_at", headerName: "Created", sortable: true, filter: true 
      ];
const gridOptions = 
        columnDefs,
        defaultColDef:  resizable: true ,
        pagination: true,
        paginationPageSize: 20
      ;
const eGridDiv = document.querySelector('#myGrid');
      new agGrid.Grid(eGridDiv, gridOptions);
// Fetch data from PHP endpoint
      fetch('api/users.php')
        .then(r => 
          if (!r.ok) throw new Error('Network response was not ok');
          return r.json();
        )
        .then(data => gridOptions.api.setRowData(data))
        .catch(err => console.error('Fetch error:', err));
    </script>
  </body>
</html>

Backend (api/users.php)

<?php
header('Content-Type: application/json');
// Simple PDO connection — adjust DSN, user, pass for your environment
$dsn = 'mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4';
$user = 'dbuser';
$pass = 'dbpass';
try 
    $pdo = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
// Basic example: return all users. For large tables, implement paging/filtering server-side.
    $stmt = $pdo->query('SELECT id, name, email, created_at FROM users ORDER BY id DESC LIMIT 500');
    $rows = $stmt->fetchAll();
echo json_encode($rows);
 catch (PDOException $e) 
    http_response_code(500);
    echo json_encode(['error' => 'Database error']);

Notes / suggestions (concise)

Related search suggestions (useful terms)

Integrating AG Grid with PHP remains a top choice for developers building data-heavy enterprise dashboards. While AG Grid is a client-side powerhouse, connecting it to a PHP backend (like Laravel or raw PHP with PDO) allows you to handle millions of rows through server-side processing.

This guide focuses on an updated implementation for 2025, utilizing modern PHP best practices and AG Grid's latest Server-Side Row Model (SSRM) features. 1. The Strategy: Server-Side Row Model (SSRM)

For large datasets, don't load everything at once. Use the SSRM to fetch data in blocks as the user scrolls.

Client-side: AG Grid sends a JSON request containing pagination, sorting, and filtering state.

Server-side (PHP): A PHP script parses this JSON, builds a dynamic SQL query, and returns only the requested "slice" of data. 2. Updated PHP Backend Implementation (Laravel Example)

Modern adapters like the AG Grid Server Side Adapter for Laravel simplify this by automatically transforming grid requests into Eloquent queries. Example Controller Snippet:

use App\Models\User; use Clickbar\AgGrid\Requests\AgGridGetRowsRequest; class UserController extends Controller public function getRows(AgGridGetRowsRequest $request) // Automatically handles filtering, sorting, and pagination return AgGridQueryBuilder::forRequest($request, User::query()) ->get(); Use code with caution. Copied to clipboard JavaScript Grid: Server-Side Row Model - AG Grid

Since you haven't pasted the specific code you are working on, I have drafted a generic code review based on the common architecture of an AG Grid integrated with a PHP backend.

This review assumes a standard setup: a PHP script returning JSON data (Server-Side) or a PHP file rendering the HTML/JS (Client-Side).

You can use this as a checklist to review your own code, or paste your code in the next message for a specific review.


3. Critical Issues & Recommendations

Step 4: Create an HTML File

Create an HTML file called "index.html" and add the following code:

<!DOCTYPE html>
<html>
<head>
    <title>AG Grid PHP Example</title>
    <script src="https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css">
    <link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-theme-balham.css">
</head>
<body>
    <div id="grid" style="height: 200px; width: 400px;" class="ag-theme-balham"></div>
    <script>
        // Fetch data from PHP script
        fetch('grid.php')
            .then(response => response.json())
            .then(data => 
                // Create AG Grid
                const gridOptions = 
                    columnDefs: [
                         field: 'name' ,
                         field: 'email' ,
                         field: 'department' 
                    ],
                    rowData: data
                ;
new agGrid.Grid(document.getElementById('grid'), gridOptions);
            );
    </script>
</body>
</html>

This HTML file includes the AG Grid library and creates a simple grid with three columns. It then fetches data from the "grid.php" script and passes it to the AG Grid.

Part 3: The Frontend (HTML + JS)

This is the "Updated" part. We use modern AG Grid syntax, enabling Enterprise-style features (like editing) using the Community version.

File: index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <title>AG Grid PHP Updated Example</title>
    <!-- Ag-Grid CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ag-grid-community/styles/ag-grid.css"/>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ag-grid-community/styles/ag-theme-alpine.css"/>
    <style>
        #myGrid  height: 500px; width: 100%; 
    </style>
</head>
<body>
<div id="myGrid" class="ag-theme-alpine"></div>
<!-- Ag-Grid JS -->
<script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
<script>
    // Define Column Definitions
    const columnDefs = [
         field: 'id', hide: true , // ID is hidden but needed for updates
         field: 'employee_name', filter: true, editable: true ,
         field: 'job_title', editable: true ,
         field: 'department', filter: true, editable: true ,
field: 'salary', 
            editable: true, 
            valueFormatter: params => '$' + params.value.toLocaleString(),
            filter: 'agNumberColumnFilter'
];
// Grid Options
    const gridOptions = 
        columnDefs: columnDefs,
        rowData: null, // Start empty
        defaultColDef: 
            flex: 1,
            minWidth: 100,
            sortable: true
        ,
        // Enable editing
        editType: 'fullRow', // Edit whole row at once
        onRowValueChanged: onRowValueChanged // Event listener for saves
    ;
// Initialize Grid
    document.addEventListener('DOMContentLoaded', () => 
        const gridDiv = document.querySelector('#myGrid');
        new agGrid.Grid(gridDiv, gridOptions);
// Fetch initial data
        fetchGridData();
    );
// Function to fetch data from PHP
    function fetchGridData() 
        // Example: Add sorting params if needed manually, or use AG Grid datasource
        fetch('api.php?action=fetch')
            .then(response => response.json())
            .then(data => 
                gridOptions.api.setRowData(data); // Updated API method
            )
            .catch(err => console.error('Error fetching data:', err));
// Function to handle data update (Backend Sync)
    function onRowValueChanged(event) 
        const newData = event.data;
console.log('Saving changes:', newData);
fetch('api.php?action=update', 
            method: 'POST',
            headers:  'Content-Type': 'application/json' ,
            body: JSON.stringify(newData)
        )
        .then(response => response.json())
        .then(res => 
            if (res.success) 
                console.log('Database updated successfully');
                // Optional: Show a toast notification
             else 
                alert('Error updating database: ' + res.message);
                // Optional: Revert the grid change
);
</script>
</body>
</html>

3. Setting Up the Database (MySQL Example)

Let’s create a sample products table with 1 million rows for scalability testing.

CREATE TABLE `products` (
  `id` int NOT NULL AUTO_INCREMENT,
  `product_name` varchar(255) NOT NULL,
  `category` varchar(100) NOT NULL,
  `price` decimal(12,2) NOT NULL,
  `stock_quantity` int NOT NULL,
  `last_updated` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_category` (`category`),
  KEY `idx_price` (`price`)
);

Insert test data (adjust for your needs):

INSERT INTO products (product_name, category, price, stock_quantity)
SELECT 
  CONCAT('Product ', SEQ),
  ELT(1 + FLOOR(RAND() * 5), 'Electronics', 'Clothing', 'Books', 'Toys', 'Furniture'),
  ROUND(RAND() * 500, 2),
  FLOOR(RAND() * 1000)
FROM 
  (SELECT @ROW := @ROW + 1 AS SEQ FROM information_schema.columns, (SELECT @ROW := 0) r LIMIT 100000) t;

🔐 Security & Performance Tips