GraphQL Pagination best practices: Using Edges vs Nodes in Connections

Aditya pratap singh
Jan 3 · 3 min read
Photo by Sam Erwin on Unsplash

There are no One-size-fit-all solutions in technology and with every choice there are tradeoffs. Knowing the caveats of our tools help us choose the optimal solution for our problem. The same goes with GraphQL connections. Even though graphql connections provides us with many useful benefits , it still can be cumbersome to design them for a production ready graphql API.

The current landscape of the pagination in GraphQL is hugely influenced by the Relay spec for Connections. GraphQL connections use cursor based pagination which is very well suited for large data sets as compared to offset based pagination (Check this excellent Slack article on this topic). Since Facebook created GraphQL the recommended Relay spec for Connections was adopted as the de-facto standard for GraphQL pagination.

GraphQL intends to make API consumption easier for Frontend developers, parts of the Relay spec contradicts this. From GraphQL spec:

Product‐centric: GraphQL is unapologetically driven by the requirements of views and the front‐end engineers that write them.


Problem:

One of the things we found consumers of GraphQL API in our organization consistently being confused was the need of the intermediate edges while using a connection. Since we were using Relay spec for Connections in our API, we never thought about this problem before. The Relay spec for connections suggests

Connection types must have fields named edges and pageInfo. Edge types must have fields named node and cursor .

Lets say we have to design Github’s GraphQL schema for organization.repositories. The Schema Definition Language(SDL) schema for this would look like below:

and the usual query for a connection looks like this

Query connection.edges for repository of organization Zalando

This unintentionally enforces most of the GraphQL API consumers to use this way of accessing the information on the nodes, even when they might not need the cursor on the connection for the next page

Solution

On some thoughts, discussion and research we found a solution which was pragmatic from the consumer’s point-of-view and also semantically intuitive. We decided to to support Connection.nodes together with Connection.edges on our connections. This solves the purpose of our consumers having to access intermediate edges on the connection. The schema definition for the connection looks like below

And the query to get the repository names from the connection is much simplified and looks like this

Query connection.nodes for repository of organization Zalando

And accessing this in the code is less cumbersome

This model is so successful that Github already supports this on their GraphQL API. The above screenshots are taken from Github’s GraphQL v4

Recommendation:

But the Connection.nodes is not a silver bullet and doesn’t replace the need for Connection.edges . When you need the cursor to paginate a really large connection object, edges are still your goto solution.

“Use Nodes when you have a finite list to use but don’t need the cursors for pagination. Use Edges when you have large list and you need to know the cursors to paginate”

References:

  1. GraphQL spec
  2. Explaining GraphQL connections
  3. Relay GraphQL Connections Specification
  4. Evolving API pagination at Slack

JavaScript in Plain English

Learn the web's most important programming language.

Thanks to Mariano Carballal

Aditya pratap singh

Written by

full-stack developer @ZalandoTech interested in web technologies, JS, GraphQL, Go, Rust and reliable distributed systems

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade