JHipster's Built-In Pagination: Free REST Paging, With a Few Strings Attached
JHipster generates paginated, filterable REST endpoints for free. Here's what you actually get, a worked curl example, and where the convenience runs out.
27 Aug 2026, 14:57 UTC

Your entity table just crossed 50,000 rows, and the endpoint that used to return "everything" now takes nine seconds and occasionally times out. The fix is pagination — and if you generated your app with JHipster, you already have it. The thesis of this post: JHipster's generated pagination and filtering support is genuinely useful out of the box, but you need to know where the defaults end and where hand-written queries begin.
What you get without writing any code
When you generate an entity with pagination enabled, JHipster wires Spring Data JPA's Pageable support directly into the generated REST resource. The controller method accepts page, size, and sort as query parameters, and the response is a page of results with pagination metadata exposed via HTTP headers (JHipster typically uses X-Total-Count plus RFC 5988 Link headers) rather than a wrapped JSON envelope. The generated Angular, React, or Vue client ships with pagination components that already understand this contract.
Because the endpoints are standard Spring MVC resources, they also inherit your Spring Security configuration automatically — a paginated endpoint is secured exactly like any other generated endpoint.
A worked example
Assume a generated Product entity. Start the app with ./mvnw spring-boot:run (run from the project root, as a user with permission to the project directory and database), then request a page:
curl -i "http://localhost:8080/api/products?page=0&size=20&sort=name,asc" \
-H "Authorization: Bearer <your-jwt>"Check the response headers for X-Total-Count and a Link header with first, prev, next, and last relations. The body is a JSON array of up to 20 items. If you get a 401, your token is missing or expired; if you get all rows with no headers, the entity was likely generated with pagination set to no — check the entity's .jhipster/Product.json for the pagination field.
For testing, Spring Data repositories accept a Pageable directly:
Page<Product> page = productRepository.findAll(PageRequest.of(0, 10));
assertThat(page.getTotalElements()).isEqualTo(expectedCount);
assertThat(page.getTotalPages()).isEqualTo(expectedPages);This runs in a standard @SpringBootTest or slice test and verifies that repository-level pagination matches what the controller exposes.
Filtering: helpful, but only for simple cases
If you enable JHipster's filtering option during entity generation, you get query-parameter filters translated into JPA criteria — equality, string contains, greater/less-than comparisons depending on field type. For example, /api/products?name.contains=shoe&price.greaterThan=100 works without any custom repository code.
The limitation is real: this covers simple per-field predicates only. Joined-entity filters, OR logic across fields, full-text search, or anything involving aggregation requires a hand-written repository method or a Specification/QueryDSL approach. Plan for that boundary early, because retrofitting complex filters into generated code is where merge pain starts on regeneration.
Trade-offs and tuning
Two things deserve attention before production:
- Default page size can hide problems. A generous default means clients rarely page deeply, but a single unbounded or oversized page can still pressure server memory. Cap the maximum page size and verify the property names in your
application.yml— these have changed across JHipster/Spring Data versions, so confirm against your generated config rather than assuming. - Deep pagination is expensive. Offset-based paging (
page=5000) forces the database to scan and discard rows. For very large tables, consider keyset (cursor) pagination on hot endpoints — that's a custom change, not a generated feature.
What to do next
Generate a scratch project, hit /api/<entities>?page=0&size=20, and confirm the X-Total-Count header matches your row count. Then add a filter parameter and verify the result set shrinks as expected. If your real queries outgrow the generated filters, isolate custom repository methods in separate classes so entity regeneration stays painless. Pagination is one of JHipster's best "free" features — just treat the defaults as a starting point, not a final configuration.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.