Lazy-Loading Large Datasets in Vaadin Grid with a Spring Data Backend
Learn how to implement a Vaadin Grid DataProvider that fetches only the rows needed for the current view, backed by a Spring Data Pageable repository, to keep UI responsive with large datasets.
10 May 2026, 19:17 UTC

Problem: Loading 100 k rows freezes the UI
When a Vaadin Grid is populated with all rows from a large table, the initial request downloads the whole dataset, consumes significant memory on the client, and can make the UI unresponsive while the browser renders thousands of rows.
Thesis: Use lazy‑loading DataProvider backed by Spring Data
Vaadin Grid’s DataProvider interface lets you supply a callback that returns only the rows needed for the current viewport, based on offset, limit, sorting and filter criteria. By wiring that callback to a Spring Data Pageable repository, you get efficient paging with almost no boilerplate.
Implementing a Spring Data‑backed DataProvider
The following class shows a minimal implementation for a Person entity.
public class PersonDataProvider extends AbstractBackEndDataProvider<Person, Void> {
private final PersonRepository personRepository;
public PersonDataProvider(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@Override
protected List<Person> fetchFromBackend(Query<Person, Void> query) {
int offset = query.getOffset();
int limit = query.getLimit();
List<OrderBy> orderBy = query.getSortOrders();
Sort sort = orderBy.isEmpty()
? Sort.unsorted()
: Sort.by(orderBy.stream()
.map(o -> o.isAscending()
? Sort.Order.asc(o.getSorted())
: Sort.Order.desc(o.getSorted()))
.collect(Collectors.toList()));
PageRequest pageRequest = PageRequest.of(offset / limit, limit, sort);
return personRepository.findAll(pageRequest).getContent();
}
@Override
protected int sizeInBackend(Query<Person, Void> query) {
return (int) personRepository.count();
}
}
Key points:
offsetandlimitcome directly from the Grid’s current viewport.- The
sortobject is translated into a Spring DataSortinstance. fetchFromBackendreturns the content of aPage;sizeInBackendreturns the total count.
Wiring the provider into the Grid
Grid<Person> grid = new Grid<>(Person.class);
grid.setDataProvider(new PersonDataProvider(personRepository));
add(grid);
Tuning, trade‑offs and verification
Lazy loading reduces initial payload but each scroll or page change triggers a new server request. If network latency is high or the page size is very small, the user may notice lag. Consider:
- Increasing the page size (e.g., 50‑100 rows) to reduce request frequency.
- Adding a simple cache (e.g., Caffeine) inside
PersonDataProviderfor recently fetched pages. - Ensuring the
PersonRepositorymethods are thread‑safe; Spring Data repositories are safe for concurrent calls. - Applying security checks before returning data; never rely on Grid‑side filtering alone.
To verify that lazy loading works:
- Run the Vaadin Flow application and open the browser’s developer tools.
- Select the Network tab and filter for XHR/fetch requests.
- Scroll the Grid or use the pager; you should see requests with query parameters resembling
offsetandlimit(often sent as JSON in the body of a POST request to the internal Vaadin endpoint). - Enable Vaadin debug mode by adding
?debugto the URL; the console will log messages likeDataProvider callback invoked with offset=0, limit=50. - Compare the initial load time and payload size with a version that uses
grid.setItems(personRepository.findAll()); the lazy version should show a much smaller first response and subsequent incremental requests.
Actionable closing
If you are working with a Vaadin Grid that could display thousands of rows, replace the eager setItems call with a DataProvider implementation that delegates to a Spring Data Pageable repository. Start with a page size of 50, monitor network traffic, and adjust size or add caching based on observed latency. This approach keeps memory usage low, reduces initial load time, and scales smoothly to datasets of hundreds of thousands of rows.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.