Pagination and connections

GraphQL · Advanced · 12 min

Any list that can grow needs pagination designed into the schema from day one.

Never expose an unbounded list such as posts: [Post!]! on a growing collection. Two styles exist:

  • Offset: posts(limit: 20, offset: 40). Simple, supports jumping to page 7, but items shift when rows are inserted, and large offsets are slow in most databases.
  • Cursor: posts(first: 20, after: "cursor"). The cursor is an opaque string (often base64 of the last sort key). Stable under inserts and efficient with keyset queries.

The widely used connection pattern (from Relay, now a general convention) standardizes cursors:

type PostConnection { edges: [PostEdge!]!  pageInfo: PageInfo!  totalCount: Int }
type PostEdge { node: Post!  cursor: String! }
type PageInfo { hasNextPage: Boolean!  endCursor: String  hasPreviousPage: Boolean!  startCursor: String }

Clients request first/after to go forward or last/before to go back. Edges are a place for relationship data (e.g. role on a team membership edge). Many APIs also add a nodes shortcut field.

Server tips: cap first (reject or clamp values above, say, 100), make cursors opaque so you can change their encoding, and implement keyset pagination (WHERE (created_at, id) < (...)) rather than translating cursors back into offsets.

Example

query Feed($after: String) {
  posts(first: 10, after: $after) {
    edges {
      cursor
      node { id title }
    }
    pageInfo { hasNextPage endCursor }
  }
}

# Next page: send variables { "after": "<pageInfo.endCursor>" }
# Stop when pageInfo.hasNextPage is false.

Remember

  • Cursor pagination is stable under inserts; offset is not
  • Connections: edges { cursor node } plus pageInfo
  • Cap page sizes and keep cursors opaque

Watch out for

  • Returning unbounded lists that grow until responses time out.

Check yourself

  1. A client has `pageInfo.endCursor = "Y3Vy"`. How does it fetch the next page?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: graphql.org/learn/pagination/

Builds on

Unlocks

Nothing builds on this yet.