Relay-Style Connections
You'll learn to
- -Implement the Relay Connection spec (edges, nodes, cursor, PageInfo) for paginating a GraphQL list field
- -Explain why this structure exists instead of just returning a plain array with a cursor argument
GraphQL needs pagination for the exact same reason REST does - an unbounded list field doesn't scale - but a plain `[User!]!` array field has no natural place to attach pagination metadata like a next cursor. The Relay Connection specification is the de facto standard structure the GraphQL ecosystem converged on to solve this.
The Connection Shape
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
endCursor: String
startCursor: String
}
type Query {
users(first: Int, after: String): UserConnection!
}- -`edges`: a wrapper around each result, pairing the actual item (`node`) with its own `cursor` - a stable position marker for that specific item, matching the cursor-pagination technique from the REST modules.
- -`node`: the actual `User` object a client cares about.
- -`pageInfo`: metadata about the page as a whole - whether more pages exist in either direction, and the cursors needed to fetch them.
- -`first`/`after`: the standard Relay arguments for forward pagination (`last`/`before` are the equivalents for paginating backward).
Why Not Just a Plain Array Plus a Cursor Argument?
query {
users(first: 10, after: "cursor_abc") {
edges {
node { id name }
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}A simpler `users(first: Int, after: String): [User!]!` returning a plain array can't express "is there a next page" or "what cursor do I use next" anywhere in its own response shape - that information would have to live somewhere else entirely, breaking the self-describing property GraphQL responses otherwise have. The Connection wrapper exists specifically to carry that pagination metadata as part of the queryable schema itself, and per-edge cursors (rather than one cursor for the whole page) let a client resume pagination from any specific item, not just the page boundary.
This structure is more verbose than a plain array, which is a real, deliberate trade-off - the ecosystem converged on it anyway because the alternative (inconsistent, ad hoc pagination metadata invented per API, or per field) was worse for tooling and client library support across the whole GraphQL ecosystem.
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.
Design Relay Connections in the API Design Lab's GraphQL Mastery act.