Pagination & Sorting in Spring Data
IntermediatePass Pageable to repository methods; Spring Data returns Page<T> with content, total elements, and page metadata; Sort can be constructed dynamically from user input.
Overview
Spring Data JPA supports pagination and sorting natively. Repository methods accept a Pageable parameter and return Page<T> (includes count query for total elements) or Slice<T> (no count query — cheaper for infinite scroll). PageRequest constructs a Pageable with page number (0-based), page size, and optional Sort. Sort can be constructed dynamically from user-supplied field names but must be validated against a whitelist to prevent SQL injection via field name. For large collections joined with @OneToMany, use @EntityGraph or JOIN FETCH to avoid in-memory pagination warnings (HHH90003004).
Basic Pagination
Extend PagingAndSortingRepository or JpaRepository and add Pageable to any method. Page<T> contains content, totalElements, totalPages, and navigation info.
public interface OrderRepository extends JpaRepository<Order, Long> {
// Simple paginated query
Page<Order> findByStatus(String status, Pageable pageable);
// Paginated with @Query
@Query("SELECT o FROM Order o WHERE o.customerId = :cid ORDER BY o.createdAt DESC")
Page<Order> findByCustomer(@Param("cid") Long customerId, Pageable pageable);
}
// Service — page 0, size 20, sort by createdAt descending
Pageable pageable = PageRequest.of(0, 20, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<Order> page = orderRepository.findByStatus("PLACED", pageable);
log.info("Page {}/{}, {} total orders",
page.getNumber(), page.getTotalPages(), page.getTotalElements());
page.getContent().forEach(o -> process(o));Slice vs Page — Avoiding the Count Query
Page<T> runs two queries: one for data + one COUNT(*) for totals. For infinite-scroll UIs where you just need hasNext(), use Slice<T> — it runs only the data query.
public interface ProductRepository extends JpaRepository<Product, Long> {
// Slice — no count query (cheaper)
Slice<Product> findByCategory(String category, Pageable pageable);
}
Pageable pageable = PageRequest.of(0, 20, Sort.by("name"));
Slice<Product> slice = productRepository.findByCategory("ELECTRONICS", pageable);
if (slice.hasNext()) {
// load next page (infinite scroll)
Pageable next = slice.nextPageable();
}Dynamic Sort with Whitelist Validation
Never pass user-supplied sort field names directly to Sort.by() — this can expose internal field names or cause injection. Validate against a whitelist map.
private static final Map<String, String> ALLOWED_SORT_FIELDS = Map.of(
"name", "name",
"price", "price",
"createdAt", "createdAt"
);
public Page<Product> search(String sortField, String direction, int page, int size) {
String safeField = ALLOWED_SORT_FIELDS.getOrDefault(sortField, "createdAt");
Sort.Direction safeDir = "asc".equalsIgnoreCase(direction)
? Sort.Direction.ASC : Sort.Direction.DESC;
Pageable pageable = PageRequest.of(page, size, Sort.by(safeDir, safeField));
return productRepository.findAll(pageable);
}Key Points to Remember
- 1Page<T> runs two queries (data + COUNT); Slice<T> runs only the data query (use for infinite scroll)
- 2PageRequest.of(page, size, sort) is 0-based — page 0 is the first page
- 3Never pass raw user input to Sort.by() — validate against a whitelist first
- 4JOIN FETCH or @EntityGraph with Pageable causes in-memory pagination — use keyset pagination instead
- 5Slice.hasNext() checks whether a next page exists without knowing the total count
- 6Sort.by("field").descending() and Sort.by(Direction, "field") are both valid
Interview Questions
Sign in to ask AriaWhat is the difference between Page<T> and Slice<T>?
Why is passing user-supplied sort field names to Sort.by() a security risk?
What page number does PageRequest.of(0, 20) represent?
What warning does Hibernate produce when you combine JOIN FETCH with Pageable?
How would you implement infinite scroll using Spring Data JPA?
Ask Aria about Pagination & Sorting in Spring Data
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.