A user scrolls through your feed. Page 1 ends with "Post 20". They tap "Next", and page 2 starts with... "Post 20" again.
Another user pages through an admin table and never sees order #4817. It exists. It is in the database. It just never showed up on any page.
Nobody changed any code. The data changed underneath the pagination, and your skip and limit could not cope.
The Code Everyone Writes
app . get ( ' /api/posts ' , async ( req , res ) => { const page = Number ( req . query . page ) || 1 ; const limit = 20 ;
const posts = await Post . find () . sort ({ createdAt : - 1 }) . skip (( page - 1 ) * limit ) . limit ( limit );
res . json ( posts ); });
Enter fullscreen mode
Exit fullscreen mode
It is simple, it works in development, and ?page=2 is easy to understand. That is why it is everywhere.
Why It Breaks
Offset pagination says "skip the first N rows, then give me the next 20". It counts positions, and positions move when the data does.
Duplicates.…