How do you do a limit query in JPQL or HQL?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
JPQL and HQL do not support a LIMIT keyword. Instead, you limit query results by calling setMaxResults() on the Query or TypedQuery object. For pagination, combine it with setFirstResult() to skip a specific number of rows. These methods translate into the appropriate SQL dialect (LIMIT, TOP, ROWNUM, or FETCH FIRST) depending on the underlying database.
Why LIMIT Does Not Exist in JPQL or HQL
Both JPQL and HQL are designed to be database-agnostic. SQL's LIMIT clause is not part of the ANSI SQL standard. It originated in MySQL and PostgreSQL, and other databases use different syntax for the same concept:
| Database | SQL Syntax |
| MySQL / PostgreSQL | SELECT * FROM t LIMIT 10 OFFSET 30 |
| SQL Server | SELECT TOP 10 * FROM t |
| Oracle (pre-12c) | WHERE ROWNUM <= 10 |
| Oracle 12c+ / ANSI SQL:2008 | FETCH FIRST 10 ROWS ONLY |
| DB2 | FETCH FIRST 10 ROWS ONLY |
Because JPQL and HQL run on top of Hibernate, which supports all of these databases, they delegate pagination to the API level rather than embedding vendor-specific syntax into the query string.
Basic Usage: setMaxResults
The simplest way to limit results is setMaxResults(). This tells Hibernate the maximum number of rows to return.
HQL Example
JPQL Example
Both examples produce the same effect: Hibernate generates a SQL query with the appropriate limit clause for the configured database dialect.
Pagination with setFirstResult and setMaxResults
For paginated results, combine setFirstResult() (the zero-based offset) with setMaxResults() (the page size).
This pattern works identically in both JPQL and HQL. The ORDER BY clause is important for pagination because without a deterministic sort order, the same row could appear on multiple pages or be skipped entirely.
Spring Data JPA: Pageable
If you are using Spring Data JPA, you rarely need to call setMaxResults() directly. The Pageable abstraction handles pagination automatically.
Usage in a service:
Under the hood, Spring Data JPA calls setFirstResult() and setMaxResults() for you.
Criteria API Alternative
For dynamic queries where JPQL strings become unwieldy, the JPA Criteria API supports the same pagination methods.
The pagination calls are on the TypedQuery object, not on the CriteriaQuery. This is a common source of confusion.
Named Queries with Limits
Named queries defined in annotations can also be paginated at call time:
You do not embed a limit in the named query string itself. The limit is always applied programmatically.
Comparison of Approaches
| Approach | Limit Support | Offset Support | Best For |
setMaxResults() on JPQL/HQL | Yes | With setFirstResult() | Standard JPA or Hibernate queries |
Spring Data Pageable | Yes | Yes | Spring Boot applications with repositories |
| Criteria API | Yes | With setFirstResult() | Dynamic queries built at runtime |
Native SQL with LIMIT | Yes | Yes | Database-specific queries (breaks portability) |
Performance Considerations
Deep Pagination is Expensive
Using a large offset with setFirstResult() forces the database to scan and discard rows before the offset point. Requesting page 1000 with 20 rows per page means the database processes 20,000 rows and discards 19,980 of them.
For large datasets, consider keyset pagination (also called seek pagination) instead:
This avoids the offset entirely by using a WHERE clause that starts from the last seen record.
Always Include ORDER BY
Without an explicit ORDER BY, the database does not guarantee row order. Paginated results without sorting can return duplicates or miss rows across pages.
Count Queries Add Overhead
Spring Data's Page return type executes a separate COUNT query to determine total elements. If you do not need the total count, use Slice instead:
Common Pitfalls
- Writing
LIMITdirectly in a JPQL or HQL string. This causes a parser error. UsesetMaxResults()instead. - Forgetting
ORDER BYwith pagination. Without a deterministic sort, rows can appear on multiple pages or be skipped. - Applying pagination to the CriteriaQuery instead of the TypedQuery. The
setMaxResults()andsetFirstResult()methods belong onTypedQuery, notCriteriaQuery. - Using deep offsets on large tables. Performance degrades linearly with offset size. Switch to keyset pagination for large datasets.
- Executing unnecessary count queries. Use
Sliceinstead ofPagein Spring Data when the total count is not needed. - Mixing Hibernate Session API with JPA EntityManager. While both support
setMaxResults(), the return types differ (list()vsgetResultList()). Pick one API and stay consistent.
Summary
- JPQL and HQL do not have a
LIMITkeyword. UsesetMaxResults()to cap the number of returned rows. - Combine
setFirstResult()withsetMaxResults()for offset-based pagination. - Spring Data JPA wraps these calls behind
PageableandPageRequestfor convenience. - Always include an
ORDER BYclause when paginating to ensure consistent results across pages. - For large datasets, prefer keyset pagination over deep offsets to avoid performance degradation.
- The Criteria API also supports pagination through the same
TypedQuerymethods.
Related reading
- How do you effectively model inheritance in a database?
- How do you get the index of the current iteration of a foreach loop?
- How do you include postgresql.conf on docker container when using org.testcontainers
- How do you like your primary keys?
- How do you manage databases in development, test, and production?
- How do you perform Django database migrations when using Docker-Compose?
- How do you query for a non-existent null attribute in DynamoDB
- How do you remove an RDS data layer from an Elastic Beanstalk environment

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.