Adding Server-Side Pagination to Backbone.js Collections
Backbone.Collection.fetch() loads every model by default. Learn to pass page parameters, track pagination state, and verify results without built-in helpers.
27 Aug 2025, 17:00 UTC

The problem: fetch loads everything
You open a view backed by a Backbone collection and the page slows down. The Network tab shows one request returning every record in the table. Backbone.Collection.fetch() sends a GET request to the collection’s url, but Backbone does not add pagination parameters by default. All models are parsed and stored in the collection at once, so memory and render time grow with your dataset.
The useful takeaway: you can paginate server-side by passing explicit query parameters in fetch(), but Backbone will not remember the current page for you. You must track page state yourself, choose whether to replace or merge models, and guard against overlapping requests.
Pass pagination parameters explicitly
fetch() accepts an options hash. Any data property you supply becomes part of the request query string. If your backend expects ?page=2&per_page=25, you must send those exact keys.
var Users = Backbone.Collection.extend({
url: '/api/users'
});
function fetchUsersPage(page, perPage) {
return users.fetch({
data: { page: page, per_page: perPage },
reset: true
});
}
reset: true tells Backbone to replace the collection’s models with the server response. Without it, Backbone adds incoming models to the ones already present, which can duplicate entries as you move between pages.
Track page state outside Backbone
Backbone does not persist the current page across navigation or refresh. Keep it in application state, the URL, or session storage.
var appState = {
page: 1,
perPage: 25
};
function goToPage(page) {
appState.page = page;
fetchUsersPage(appState.page, appState.perPage);
}
Update appState.page before calling fetch() so the UI and the request stay in sync. If you need the page to survive a refresh, write it to the URL query string or sessionStorage in the same function.
Verify the request and the result
Open browser developer tools, open the Network tab, and trigger a page change. Confirm the request URL includes the expected parameters and that the response contains only the subset for that page. After the request completes, check the collection in the console:
console.log(users.length);
Compare that number with the page size you requested and with the total count returned by your API, if available. A mismatch usually means the backend ignored your parameters or returned an error payload instead of a model array.
Limitations and race conditions
- Parameter name mismatches fail silently: the server may return all models or none, and Backbone will not warn you.
- Large
perPagevalues increase browser memory because every retrieved model stays in the collection. - Concurrent fetches can race. If a user clicks page two and then page one quickly, the slower response may arrive last and overwrite fresher data. Disable pagination controls while a request is in flight, or keep a reference to the request and call
abort()before starting a new one. reset: truereplaces models without a built-in undo. Keep a copy of the previous models if you need to revert after a bad response.
Start with the Network tab
Add one data hash to your next fetch() call, track the page number in a plain object, and verify the URL and response length in developer tools. Only add abort logic or URL synchronization after you confirm the basic request behaves as expected.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.