Convert SQL LIMIT and OFFSET to MongoDB limit() and skip()

Learn how SQL LIMIT and OFFSET for pagination translate to MongoDB limit() and skip() cursor methods or $limit and $skip pipeline stages.

Migration

Detailed Explanation

LIMIT / OFFSET to limit() / skip()

SQL uses LIMIT and OFFSET for pagination. MongoDB provides limit() and skip() cursor methods, or $limit and $skip aggregation stages.

Example SQL

SELECT * FROM articles
ORDER BY created_at DESC
LIMIT 20 OFFSET 40

Generated MongoDB Query (find)

db.articles.find({}).sort({
  created_at: -1
}).skip(40).limit(20)

Generated MongoDB Query (aggregate)

db.articles.aggregate([
  { $sort: { created_at: -1 } },
  { $skip: 40 },
  { $limit: 20 }
])

Pagination Pattern

The standard offset-based pagination maps directly:

  • Page 1: LIMIT 20 OFFSET 0 = .skip(0).limit(20)
  • Page 2: LIMIT 20 OFFSET 20 = .skip(20).limit(20)
  • Page 3: LIMIT 20 OFFSET 40 = .skip(40).limit(20)

LIMIT Without OFFSET

A simple LIMIT without OFFSET (starting from the beginning) only needs .limit():

SELECT * FROM users LIMIT 10
db.users.find({}).limit(10)

Performance Warning for Large Offsets

MongoDB's skip() still scans and discards the skipped documents, meaning performance degrades linearly with the offset value. For large collections, cursor-based (keyset) pagination is recommended:

// Instead of skip(10000).limit(20), use:
db.articles.find({
  created_at: { $lt: lastSeenDate }
}).sort({ created_at: -1 }).limit(20)

This approach uses an indexed field to efficiently seek to the correct position.

Method Chain Order

For find() queries, .sort(), .skip(), and .limit() can be chained in any order — MongoDB always applies them as sort first, then skip, then limit. In the aggregate pipeline, however, the order of stages matters and must be explicit.

Use Case

Every web application with paginated list views — blog posts, search results, admin tables — relies on LIMIT/OFFSET pagination. Understanding the MongoDB equivalents and their performance characteristics is essential for maintaining responsive APIs after migration.

Try It — SQL to MongoDB Query

Open full tool