Skip to content

Data sources and rows

InertiaX executes both database-backed and in-memory Tables. Source kind matters: built-in operations preserve equivalent meaning, while custom operations must declare the kinds they actually support.

UsersTable::make('users')->data(
User::query()->where('account_id', $account->id),
)

The builder remains lazy. Filters, search, sorting, and pagination are applied before rows are retrieved.

UsersTable::make('users')->data(User::class)

The model class is normalized to User::query().

AuditEventsTable::make('audit_events')->data(
collect([
['id' => 1, 'event' => 'Account created', 'actor' => 'Ada Lovelace'],
['id' => 2, 'event' => 'Role changed', 'actor' => 'Grace Hopper'],
]),
)

Laravel and Eloquent Collections are accepted. Eloquent Collections are treated as an in-memory snapshot, not converted back into a query.

UsersTable::make('users')->data([
['id' => 1, 'name' => 'Ada'],
['id' => 2, 'name' => 'Grace'],
])

Arrays normalize to a Laravel Collection.

Use a closure when resolving the source requires request or container context:

UsersTable::make('users')->data(
fn () => User::query()->whereBelongsTo(auth()->user()->account),
)

The callback is evaluated during Table materialization and must return one of the supported source types. Authorization and tenant scoping should already be enforced by this source; the frontend is not an authorization boundary.

Reusable Tables can own their source:

class ActiveUsersTable extends Table
{
protected function data(): mixed
{
return User::query()->where('active', true);
}
}

A fluent ->data(...) call at the use site overrides it. This is useful when a shared definition needs a page-specific query.

Each result row must have a stable, unique key.

  • Eloquent builders use the model’s configured primary key.
  • Collections of models use the model primary key.
  • Arrays and ordinary Collections default to id.
  • Call rowKey('uuid') when the source uses another field.
SessionsTable::make('sessions')
->data($sessions)
->rowKey('uuid')

Row keys drive selection, rendering identity, and state reconciliation. Missing or duplicate identity is invalid; do not use a changing display value as the key. Numeric identities must be JavaScript-safe integers. Return database IDs above that range as exact strings rather than numbers.

For every source, Table operations run in this order:

  1. filters;
  2. global search;
  3. sorting;
  4. pagination;
  5. row and cell serialization.

This is why a page count reflects the filtered result and why sorting happens before the page is sliced. Definitions are replay-safe: materializing the same reusable Table for another request starts from a fresh source and fresh feature definitions.

Prefer an Eloquent builder for database-backed, potentially large data. It keeps filtering, sorting, and pagination in SQL. Use Collections for already-materialized domain data or bounded datasets. A custom operation that only has a valid SQL meaning should support Eloquent only and fail clearly on a Collection rather than silently changing semantics.