Help us improve
Share bugs, ideas, or general feedback.
From api-pagination
Implements offset, cursor, and keyset pagination strategies for APIs handling large datasets. Use for paginated endpoints, infinite scroll, or optimizing database collection queries.
npx claudepluginhub secondsky/claude-skills --plugin api-paginationHow this skill is triggered — by the user, by Claude, or both
Slash command
/api-pagination:api-paginationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Implement scalable pagination strategies for handling large datasets efficiently.
Explains offset/limit pagination tradeoffs: page drift, deep offset performance costs, and COUNT(*) overhead. Useful when reviewing PRs, designing list endpoints, or evaluating migration to cursor pagination.
Designs API response formats with consistent envelopes, Stripe-style cursor pagination, offset/keyset pagination, list endpoints, and expandable objects for stable client contracts.
Provides REST API design patterns for resource naming, URL structures, HTTP methods/status codes, pagination, filtering, errors, versioning, and rate limiting.
Share bugs, ideas, or general feedback.
Implement scalable pagination strategies for handling large datasets efficiently.
| Strategy | Best For | Performance |
|---|---|---|
| Offset/Limit | Small datasets, simple UI | O(n) |
| Cursor | Infinite scroll, real-time | O(1) |
| Keyset | Large datasets | O(1) |
app.get('/products', async (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 [products, total] = await Promise.all([
Product.find().skip(offset).limit(limit),
Product.countDocuments()
]);
res.json({
data: products,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit)
}
});
});
app.get('/posts', async (req, res) => {
const limit = 20;
const cursor = req.query.cursor;
const query = cursor
? { _id: { $gt: Buffer.from(cursor, 'base64').toString() } }
: {};
const posts = await Post.find(query).limit(limit + 1);
const hasMore = posts.length > limit;
if (hasMore) posts.pop();
res.json({
data: posts,
nextCursor: hasMore ? Buffer.from(posts[posts.length - 1]._id).toString('base64') : null
});
});
{
"data": [...],
"pagination": {
"page": 2,
"limit": 20,
"total": 150,
"totalPages": 8
},
"links": {
"first": "/api/products?page=1",
"prev": "/api/products?page=1",
"next": "/api/products?page=3",
"last": "/api/products?page=8"
}
}