Paginate Extbase Data with TYPO3’s Pagination API – A Practical Guide
Learn how to paginate large Extbase result sets in TYPO3 using the built‑in Pagination API, with code snippets, verification steps, and best‑practice warnings.
18 Jun 2026, 20:19 UTC

Problem & Takeaway
Editors often need to list thousands of records—news, products, or custom entities—without slowing the frontend. Pulling every record into PHP and slicing it in Fluid is memory‑heavy and slow. The solution is to let the database do the heavy lifting and only fetch the slice you need, using Extbase’s repository together with TYPO3’s built‑in Pagination API.
1. Configure the Repository for Pagination
In Extbase, the repository is where you build queries. A dedicated method that accepts the current page and items per page keeps the logic encapsulated.
public function findPaginated(int $page, int $itemsPerPage): QueryResult
{
$query = $this->createQuery();
// If the data lives in multiple storage pages or languages, disable the defaults
$query->getQuerySettings()
->setRespectStoragePage(false)
->setRespectSysLanguage(false);
// Calculate offset for the current page
$offset = ($page - 1) * $itemsPerPage;
// Apply limit and offset then execute
return $query
->setLimit($itemsPerPage)
->setOffset($offset)
->execute();
}
⚠️ Risk: Disabling storage page or language globally can expose data from hidden sections. Keep the disabling scoped to the repository method and document the intent.
2. Inject Pagination in the Controller
The controller should wrap the QueryResult in a Pagination object, which carries total count and navigation data for Fluid.
public function listAction(): Response
{
$page = (int)($this->request->getQueryParams()['p'] ?? 1);
$itemsPerPage = 10;
$queryResult = $this->myRepository->findPaginated($page, $itemsPerPage);
$pagination = new \TYPO3\CMS\Core\Pagination\Pagination(
$queryResult,
$itemsPerPage,
$page
);
return $this->render('MyExtension/View/Controller/List', [
'items' => $queryResult->toArray(),
'pagination' => $pagination
]);
}
3. Render with Fluid
Fluid’s <f:widget.paginate> widget consumes the Pagination object and generates navigation links. The list of items is rendered normally.
<ul>
<f:for each="{items}" as="item">
<li><f:link.page pageUid="{item.pageUid}">{item.title}</f:link.page></li>
</f:for>
</ul>
<f:widget.paginate paginate="{pagination}" />
4. Verify the Implementation
- Open the TYPO3 backend, go to Reports > SQL Profiler and trigger a page request. Confirm the generated SQL contains
LIMIT 10 OFFSET 0for the first page,LIMIT 10 OFFSET 10for the second, etc. - Clear the frontend and backend caches after changing query settings; TYPO3 may cache the output otherwise.
- Write a unit test in
Tests/Unit/Repository/MyRepositoryTest.phpthat asserts thePaginationobject holds the expected number of records for page 2 when 25 records exist.
5. Trade‑offs & Limitations
Extbase pagination abstracts the paging logic, which simplifies controller code and improves testability. However, the underlying SQL still depends on proper indexing. If you filter on a non‑indexed column, the database will perform a full table scan before applying LIMIT, negating the performance benefit. Always inspect the generated SQL and add indexes where necessary.
Another subtle point: setRespectStoragePage(false) and setRespectSysLanguage(false) should not be used globally. They are only safe when the repository is tightly scoped to a single extension that intentionally aggregates data across pages or languages.
Actionable Takeaway
To display large lists efficiently in TYPO3:
- Implement a
findPaginated()method in your repository that setslimitandoffset. - Wrap the
QueryResultin aPaginationobject in the controller. - Use
<f:widget.paginate>in Fluid to render navigation. - Verify the SQL contains
LIMIT/OFFSETand that cache clearing is performed after changes. - Ensure indexes support the query’s where conditions to keep performance optimal.
Following these steps yields a maintainable, testable, and performant paginated list that scales with your data volume.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.