Restful Pagination
title: "RESTful Pagination — Page-Based and Cursor-Based Pagination" description: "RESTful pagination provides page-based or cursor-based navigation for large collections, using consistent query parameters and metadata in responses." date: 2026-06-28 lastmod: 2026-06-28 weight: 17 tags: [apis, restful] }
RESTful pagination splits large resource collections into manageable pages using standard query parameters with consistent response metadata for navigation.
What You'll Learn
- Page-based pagination
- Cursor-based pagination
- Pagination metadata conventions
Why It Matters
Without pagination, large collections overwhelm clients and servers. Consistent pagination conventions let clients handle any size dataset efficiently.
Code Examples
# Page-based pagination
@app.route('/users')
def list_users():
page = request.args.get('page', 1, type=int)
limit = min(request.args.get('limit', 20, type=int), 100)
offset = (page - 1) * limit
total = db.count_users()
total_pages = (total + limit - 1) // limit
users = db.get_users(limit=limit, offset=offset)
return jsonify({
"data": [u.to_dict() for u in users],
"pagination": {
"page": page,
"limit": limit,
"total": total,
"total_pages": total_pages,
"has_next": page < total_pages,
"has_prev": page > 1
}
})
# Cursor-based pagination
@app.route('/orders')
def list_orders():
cursor = request.args.get('cursor')
limit = min(request.args.get('limit', 20, type=int), 100)
if cursor:
cursor_id = decode_cursor(cursor)
orders = db.execute(
"SELECT * FROM orders WHERE id > ? ORDER BY id LIMIT ?",
[cursor_id, limit + 1]
)
else:
orders = db.execute(
"SELECT * FROM orders ORDER BY id LIMIT ?",
[limit + 1]
)
has_more = len(orders) > limit
orders = orders[:limit]
next_cursor = encode_cursor(orders[-1]['id']) if has_more else None
return jsonify({
"data": orders,
"pagination": {
"next_cursor": next_cursor,
"has_more": has_more
}
})
app.get('/api/users', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
const offset = (page - 1) * limit;
const { users, total } = db.getUsers(limit, offset);
res.json({
data: users,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
hasNext: page * limit < total,
hasPrev: page > 1
}
});
});
Common Mistakes
1. No Default Pagination
Returning all results when no pagination params provided.
2. No Limit on Page Size
Clients request 10,000 items per page, overwhelming the server.
3. Inconsistent Parameter Names
Mix of page, offset, limit, per_page across endpoints.
4. Missing Pagination Metadata
Clients can't determine total results or navigate pages.
5. No Cursor Encoding
Exposing raw database IDs in cursor values.
Practice Questions
- What is the default page size recommendation?
- What parameters control page-based pagination?
- What parameters control cursor-based pagination?
- Why use cursor pagination over page-based?
- What metadata should pagination responses include?
Answers:
- 20-30 items per page, with a maximum of 100.
pageandlimit(orper_page).cursorandlimit.- Stable results for real-time data and better performance at scale.
- Page, limit, total, total_pages, has_next, has_prev (or cursor equivalents).
Challenge: Implement both page-based and cursor-based pagination for a REST endpoint. Let clients choose which to use.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro