Offset pagination is the tutorial answer. Cursor pagination is the production answer.
The moment your data mutates while someone paginates, offsets start skipping and duplicating rows. Cursors encode a stable position, so the page you get is the page you meant.
Return an opaque cursor, never a raw row id you might change.
Make the cursor encode the sort key + tiebreaker.
Document that cursors are not forever.