# Cursor Pagination

> Cursor-based pagination request and response with next cursor and has-more flag.

- Name: `cursor-pagination`
- Categories: api
- Detail page: https://open-types.dev/types/cursor-pagination

## Install

```bash
# Types only
npx shadcn add @open-types/cursor-pagination

# Types + Zod v4 validators
npx shadcn add @open-types/cursor-pagination-zod

# Types + real-world examples
npx shadcn add @open-types/cursor-pagination-examples
```

## Types

```typescript
export interface CursorPaginationRequest {
  cursor?: string;
  limit?: number;
}

export interface CursorPaginationResponse {
  items: unknown[];
  next_cursor: string | null;
  has_more: boolean;
  total?: number;
}
```

## Zod validator

```typescript
import * as z from "zod";
import type {
  CursorPaginationRequest,
  CursorPaginationResponse,
} from "../types/cursor-pagination";

export const cursorPaginationRequestSchema = z.object({
  cursor: z.string().optional(),
  limit: z
    .number()
    .int()
    .min(1, { error: "Limit must be at least 1" })
    .max(100, { error: "Limit must be at most 100" })
    .default(20)
    .optional(),
}) satisfies z.ZodType<CursorPaginationRequest>;

export const cursorPaginationResponseSchema = z.object({
  items: z.array(z.unknown()),
  next_cursor: z.string().nullable(),
  has_more: z.boolean(),
  total: z.number().int().min(0).optional(),
}) satisfies z.ZodType<CursorPaginationResponse>;

export type {
  CursorPaginationRequest,
  CursorPaginationResponse,
} from "../types/cursor-pagination";
```

## Examples

```typescript
// Source: hand-crafted
import type {
  CursorPaginationRequest,
  CursorPaginationResponse,
} from "../types/cursor-pagination";

export const cursorPaginationRequestExamples = {
  empty: {} satisfies CursorPaginationRequest,
  firstPage: { limit: 50 } satisfies CursorPaginationRequest,
  next: { cursor: "eyJpZCI6MTAwfQ==", limit: 50 } satisfies CursorPaginationRequest,
  cursorOnly: { cursor: "Y3Vyc29yOnYyOnByZXY=" } satisfies CursorPaginationRequest,
  maxLimit: { limit: 100 } satisfies CursorPaginationRequest,
} as const;

export const cursorPaginationResponseExamples = {
  hasMore: {
    items: [{ id: "1" }, { id: "2" }, { id: "3" }],
    next_cursor: "eyJpZCI6Mn0=",
    has_more: true,
  } satisfies CursorPaginationResponse,
  hasMoreWithTotal: {
    items: [{ id: "1" }, { id: "2" }],
    next_cursor: "eyJpZCI6Mn0=",
    has_more: true,
    total: 482,
  } satisfies CursorPaginationResponse,
  exhausted: {
    items: [{ id: "100" }, { id: "101" }],
    next_cursor: null,
    has_more: false,
  } satisfies CursorPaginationResponse,
  empty: {
    items: [],
    next_cursor: null,
    has_more: false,
    total: 0,
  } satisfies CursorPaginationResponse,
} as const;
```
