Skip to content

Results, Sorting & Pagination

Offset Pagination

page × pageSize with skip and limit, and the point at which it starts to hurt.

IntermediateAbout 5 minutes

Offset pagination is what every admin table expects: ?page=3&pageSize=10. You skip((page - 1) * pageSize).limit(pageSize) on a sorted cursor. It is simple. It is correct enough for small data. It is the wrong default for a public feed of millions of orders.

const page = 3;
const pageSize = 10;

db.products
  .find({ inStock: true })
  .sort({ price: 1, _id: 1 })
  .skip((page - 1) * pageSize)
  .limit(pageSize)
Page 3, 10 per page. Sort is not optional.
const filter = { inStock: true };
const [items, total] = await Promise.all([
  products.find(filter).sort({ price: 1, _id: 1 }).skip(20).limit(10).toArray(),
  products.countDocuments(filter),
]);
Node — same idea. Total count is a second query if you need 'page 3 of 40'.
  • Good for — internal tools, a few thousand rows, jumping to page 12.
  • Hurts whenskip is large (walks every prior document), or rows insert/delete while someone pages (page 2 duplicates or skips a product).
  • CountcountDocuments on the same filter is another full pass. Many UIs drop 'of N' and only show Next.

Interview question

When is skip/limit pagination acceptable, and when is it not?

Think about it first.