Skip to main content

PageInfo Type

The PageInfo type provides pagination information for list queries.

Type Definition

"""
Information about pagination in a connection.
"""
type PageInfo {
"""
Indicates if there are more pages after the current one.
"""
hasNextPage: Boolean!

"""
Indicates if there are previous pages before the current one.
"""
hasPreviousPage: Boolean!

"""
Cursor to use for getting the next page.
"""
endCursor: String

"""
Cursor to use for getting the previous page.
"""
startCursor: String
}

Fields

FieldTypeDescription
hasNextPageBoolean!Required. Whether there are more items
hasPreviousPageBoolean!Required. Whether there are previous items
endCursorStringOptional. Cursor for next page
startCursorStringOptional. Cursor for previous page

Usage

In List Queries

query GetLocationHistory {
locationHistory(trackerId: "tracker_123", first: 10, after: "cursor_xyz") {
nodes {
id
timestamp
}
pageInfo {
hasNextPage
endCursor
hasPreviousPage
startCursor
}
totalCount
}
}

Forward Pagination

query GetNextPage {
trackers(first: 10, after: "cursor_xyz") {
nodes {
id
status
}
pageInfo {
hasNextPage
endCursor
}
}
}

Backward Pagination

query GetPreviousPage {
trackers(last: 10, before: "cursor_xyz") {
nodes {
id
status
}
pageInfo {
hasPreviousPage
startCursor
}
}
}

Pagination Patterns

Connection Pattern

"""
A connection pattern for paginated lists.
"""
type TrackerConnection {
"""
List of tracker nodes.
"""
nodes: [Tracker!]!

"""
Pagination information.
"""
pageInfo: PageInfo!

"""
Total count of items available.
"""
totalCount: Int!
}

Cursor-based Navigation

type Query {
"""
Get a paginated list of trackers.
"""
trackers(
"""
Number of items to fetch going forward.
"""
first: Int

"""
Number of items to fetch going backward.
"""
last: Int

"""
Cursor to fetch items after.
"""
after: String

"""
Cursor to fetch items before.
"""
before: String
): TrackerConnection!
}

Best Practices

  1. Cursor Handling

    • Use opaque cursors
    • Base64 encode cursor data
    • Include sorting information
  2. Page Sizes

    • Set reasonable defaults
    • Enforce maximum limits
    • Document limitations
  3. Performance

    • Use efficient cursor encoding
    • Optimize cursor queries
    • Cache common pages
  4. Error Handling

    • Validate cursor format
    • Handle invalid cursors
    • Provide clear error messages

Implementation Example

interface PaginationArgs {
first?: number;
last?: number;
after?: string;
before?: string;
}

interface Connection<T> {
nodes: T[];
pageInfo: PageInfo;
totalCount: number;
}

async function createConnection<T>(
args: PaginationArgs,
fetchFn: (args: PaginationArgs) => Promise<T[]>,
countFn: () => Promise<number>,
): Promise<Connection<T>> {
const limit = args.first || args.last || 10;
const nodes = await fetchFn(args);
const totalCount = await countFn();

return {
nodes,
pageInfo: {
hasNextPage: nodes.length === limit,
hasPreviousPage: !!args.after || !!args.before,
startCursor: nodes[0]?.id,
endCursor: nodes[nodes.length - 1]?.id,
},
totalCount,
};
}