How does pagination and sorting work with Pageable and Page?

8 minintermediatepaginationpageablesorting

Quick Answer

A repository method that accepts a Pageable parameter (typically built via PageRequest.of(pageNumber, pageSize, sort)) automatically applies the corresponding LIMIT/OFFSET and ORDER BY to its query, and returning a Page<T> (rather than a plain List<T>) additionally gives you the total element/page count, computed via an extra count query Spring Data generates automatically. Sort can be composed independently or combined into the Pageable itself, letting a single repository method support arbitrary client-driven paging and ordering without custom query code.

Detailed Answer

Spring Data JPA has built-in support for pagination and sorting via the Pageable and Sort abstractions, without requiring any custom LIMIT/OFFSET query logic.

Declaring a paginated repository method:

public interface OrderRepository extends JpaRepository<Order, Long> {
    Page<Order> findByStatus(String status, Pageable pageable);
}

Building a Pageable and calling it:

Sort sort = Sort.by(Sort.Direction.DESC, "createdAt");
Pageable pageable = PageRequest.of(0, 20, sort); // page 0 (first page), 20 items per page, sorted

Page<Order> page = orderRepository.findByStatus("SHIPPED", pageable);

Spring Data translates this into the appropriate LIMIT/OFFSET (or database-specific equivalent) plus ORDER BY clause automatically — no manual SQL needed.

Page<T> vs Slice<T> vs plain List<T>:

  • Page<T> additionally provides getTotalElements() and getTotalPages() — but computing these requires Spring Data to run an additional COUNT query alongside the main query, which has a real performance cost on very large tables.
  • Slice<T> provides hasNext()/hasPrevious() (useful for infinite-scroll-style "load more" UIs) without the extra count query — cheaper when you don't actually need a total count.
  • A plain List<T> combined with a Pageable parameter still applies paging/sorting, but returns no metadata about total pages at all.
@RestController
class OrderController {
    @GetMapping("/orders")
    Page<Order> listOrders(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "20") int size,
        @RequestParam(defaultValue = "createdAt,desc") String sort) {
        Pageable pageable = PageRequest.of(page, size, Sort.by(parseSort(sort)));
        return orderRepository.findByStatus("SHIPPED", pageable);
    }
}

Spring MVC can also automatically resolve a Pageable method parameter directly from request query parameters (?page=0&size=20&sort=createdAt,desc) via PageableHandlerMethodArgumentResolver, which Spring Boot's web auto-configuration wires up by default — letting a controller accept a Pageable parameter directly without manually parsing query parameters at all.