Processwire Pagination: Built-in vs Custom Library Decision Guide
Choose Processwire's built-in pagination for lists under 200 items. For large datasets or deep pagination, consider cursor-based custom libraries—but you'll need to manually handle access control.
24 Sept 2026, 06:53 UTC

The Problem: Slow Page Loads on Deep Pagination
When building list views in Processwire, you face a key decision: use the built-in limit/offset pagination or implement a custom library. The choice impacts performance, development time, and whether Processwire's access control stays intact. For small to medium lists (<200 items), built-in pagination is simpler. For large datasets or deep pages, a custom cursor-based approach may be necessary.
Decision Constraints
- Data size: Number of pages and items per page
- Performance requirements: Load times for deep pagination
- Feature needs: Infinite scroll, cursor-based navigation
- Security requirements: Must preserve Processwire's access control and language filters
- Development resources: Time available for implementation
Comparison Table
| Feature | Built-in Pagination | Custom Library |
|---|---|---|
| Integration | Yes (native) | Yes (manual) |
| Performance | Fast for small sets | Cursor-based can be faster for large sets |
| Flexibility | Limited | Extensive |
| Development time | Low | High |
| Memory overhead | Low | High |
| Access control | Automatic | Manual implementation required |
Trade-offs Explained
Built-in pagination uses SQL OFFSET under the hood, which becomes inefficient for deep pages (page > 50) or very large datasets because the database must scan and skip all preceding rows. However, it automatically applies Processwire's access control, language filters, and other API features without additional code.
Custom libraries can implement cursor-based pagination, which uses a unique identifier from the last item to fetch the next set, avoiding the performance penalty of OFFSET. This approach scales better for large datasets but requires you to manually replicate Processwire's access control logic, increasing complexity and potential security gaps.
Concrete Implementation: Built-in Pagination
Run this code in a Processwire template file to implement standard pagination:
$pages = wire('pages');
$limit = 20;
$page = (int) input()->get('page');
$page = $page > 0 ? $page : 1;
$offset = ($page - 1) * $limit;
// Get paginated results - access control automatically applied
$results = $pages->find("template=article, limit=$limit, start=$offset");
// Display items
foreach($results as $p) {
echo '' . $p->title . '
';
echo '' . substr($p->body, 0, 150) . '...
';
}
// Build pagination links
$totalItems = $pages->count("template=article");
$totalPages = ceil($totalItems / $limit);
echo '';
for($i = 1; $i <= $totalPages; $i++) {
$class = ($i == $page) ? ' class="active"' : '';
echo '' . $i . ' ';
}
echo '';
Validation Strategy
- Create test data: Generate 200 article pages in Processwire
- Enable pagination: Set limit=20 and test navigation to page 10
- Verify item count: Confirm exactly 20 items appear per page
- Check SQL queries: Enable database query logging to verify OFFSET values
- Measure performance: Time page loads with and without pagination
When to Consider a Custom Library
Switch to a custom cursor-based solution if:
- You have >1000 items and users frequently access pages beyond page 20
- You need infinite scroll or real-time loading features
- Performance testing shows OFFSET queries taking >500ms for deep pages
Warning: If using a custom library, you must manually apply Processwire's access control by adding include="hide-unpublished,unmanaged" and sort="sort" to your queries, and explicitly check $page->viewable() for each result.
Quick Performance Check
To verify your pagination is working correctly, add this debug code:
echo "";
echo "";
Check the HTML source to confirm the correct number of items and SQL structure.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.