Skip to content

Graphql Connections

DodaTech 2 min read

title: "GraphQL Connections — Relay Pagination for GraphQL APIs" description: "GraphQL Relay connections provide cursor-based pagination with edges, nodes, and pageInfo, offering a standardized approach for paginating GraphQL queries." date: 2026-06-28 lastmod: 2026-06-28 weight: 22 tags: [apis, pagination] }

GraphQL Relay connections implement cursor-based pagination using edges (with cursors) and nodes (the actual data), providing stable, reusable pagination.

What You'll Learn

  • Relay connection specification
  • Edges, nodes, and pageInfo
  • forward/backward pagination arguments

Why It Matters

Relay connections are the standard pagination pattern for GraphQL APIs. Any GraphQL client expecting Relay pagination can consume your API.

Connection Structure

type Query {
  users(first: Int, after: String, last: Int, before: String): UserConnection
}

type UserConnection {
  edges: [UserEdge]
  pageInfo: PageInfo!
}

type UserEdge {
  node: User!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

Code Examples

# GraphQL Relay connection resolver
import graphene
from graphene import relay

class User(graphene.ObjectType):
    id = graphene.ID()
    name = graphene.String()
    email = graphene.String()

class UserConnection(relay.Connection):
    class Meta:
        node = User

class Query(graphene.ObjectType):
    users = relay.ConnectionField(UserConnection)

    def resolve_users(self, info, first=None, after=None, **kwargs):
        query = User.get_query(info)
        return relay.ConnectionFromIterable.resolve_connection(
            UserConnection, query, args={"first": first, "after": after}
        )

# Server-side resolver with cursor logic
def resolve_users(self, info, first=None, after=None):
    limit = first or 20
    cursor = decode_cursor(after) if after else None

    if cursor:
        users = db.execute(
            "SELECT * FROM users WHERE id > %s ORDER BY id LIMIT %s",
            [cursor, limit + 1]
        )
    else:
        users = db.execute(
            "SELECT * FROM users ORDER BY id LIMIT %s",
            [limit + 1]
        )

    has_next = len(users) > limit
    if has_next:
        users = users[:limit]

    edges = [
        {"node": u, "cursor": encode_cursor(u.id)}
        for u in users
    ]

    return {
        "edges": edges,
        "pageInfo": {
            "hasNextPage": has_next,
            "hasPreviousPage": False,
            "startCursor": edges[0]["cursor"] if edges else None,
            "endCursor": edges[-1]["cursor"] if edges else None
        }
    }

Common Mistakes

1. Not Following Relay Spec

Use first/after for forward and last/before for backward pagination.

2. Missing pageInfo

hasNextPage and hasPreviousPage are required in the connection spec.

3. Cursors Not Opaque

Cursors should be base64-encoded strings, not raw database IDs.

4. No Total Count

Relay connections don't require total count, but you can add it.

5. Incorrect hasNextPage Logic

Fetch limit + 1 items. If you get more than limit, there's a next page.

Practice Questions

  1. What are the three main parts of a Relay connection?
  2. What arguments control forward pagination?
  3. What arguments control backward pagination?
  4. Why are cursors opaque to clients?
  5. How do you determine hasNextPage?

Answers:

  1. edges, nodes (in edges), and pageInfo.
  2. first (count) and after (cursor).
  3. last (count) and before (cursor).
  4. So clients don't depend on cursor format, allowing server-side changes.
  5. Fetch n+1 items; if you get n+1, hasNextPage = true.

Challenge: Implement a GraphQL Relay connection for a blog with posts and comments. Support both forward and backward pagination with proper pageInfo.

FAQ

Is Relay pagination only for GraphQL?

: Yes. Relay connections are a GraphQL-specific pagination pattern.

Can I use Relay pagination with REST?

: The concept translates, but Relay is designed for GraphQL.

What is the benefit of edges over direct nodes?

: Edges attach metadata (cursor) to each item, enabling stable pagination.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro