> api-pagination

Implements efficient API pagination using offset, cursor, and keyset strategies for large datasets. Use when building paginated endpoints, implementing infinite scroll, or optimizing database queries for collections.

fetch
$curl "https://skillshub.wtf/secondsky/claude-skills/api-pagination?format=md"
SKILL.mdapi-pagination

API Pagination

Implement scalable pagination strategies for handling large datasets efficiently.

Pagination Strategies

StrategyBest ForPerformance
Offset/LimitSmall datasets, simple UIO(n)
CursorInfinite scroll, real-timeO(1)
KeysetLarge datasetsO(1)

Offset Pagination

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)
    }
  });
});

Cursor Pagination

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
  });
});

Response Format

{
  "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"
  }
}

Best Practices

  • Set reasonable max limits (e.g., 100)
  • Use cursor pagination for large datasets
  • Index sorting fields
  • Avoid COUNT queries when possible
  • Never allow unlimited page sizes

> related_skills --same-repo

> zustand-state-management

--- name: zustand-state-management description: Zustand state management for React with TypeScript. Use for global state, Redux/Context API migration, localStorage persistence, slices pattern, devtools, Next.js SSR, or encountering hydration errors, TypeScript inference issues, persist middleware problems, infinite render loops. Keywords: zustand, state management, React state, TypeScript state, persist middleware, devtools, slices pattern, global state, React hooks, create store, useBoundS

> zod

TypeScript-first schema validation and type inference. Use for validating API requests/responses, form data, env vars, configs, defining type-safe schemas with runtime validation, transforming data, generating JSON Schema for OpenAPI/AI, or encountering missing validation errors, type inference issues, validation error handling problems. Zero dependencies (2kb gzipped).

> xss-prevention

--- name: xss-prevention description: XSS attack prevention with input sanitization, output encoding, Content Security Policy. Use for user-generated content, rich text editors, web application security, or encountering stored XSS, reflected XSS, DOM manipulation, script injection errors. Keywords: sanitization, HTML-encoding, DOMPurify, CSP, Content-Security-Policy, rich-text-editor, user-input, escaping, innerHTML, DOM-manipulation, stored-XSS, reflected-XSS, input-validation, output-encodi

> wordpress-plugin-core

--- name: wordpress-plugin-core description: WordPress plugin development with hooks, security, REST API, custom post types. Use for plugin creation, $wpdb queries, Settings API, or encountering SQL injection, XSS, CSRF, nonce errors. Keywords: wordpress plugin development, wordpress security, wordpress hooks, wordpress filters, wordpress database, wpdb prepare, sanitize_text_field, esc_html, wp_nonce, custom post type, register_post_type, settings api, rest api, admin-ajax, wordpress sql inj

┌ stats

installs/wk0
░░░░░░░░░░
github stars100
██████████
first seenApr 3, 2026
└────────────