Paginate Large Result Sets
The Geo API uses cursor-based pagination (Relay-style). Every list query has a Connection variant that returns totalCount, pageInfo, and an opaque endCursor you pass back to fetch the next page.
The pattern — query
query Page($spaceId: UUID!, $typeId: UUID!, $after: Cursor) {
entitiesConnection(
spaceId: $spaceId
typeId: $typeId
first: 100
after: $after
) {
totalCount
pageInfo {
hasNextPage
endCursor
}
nodes {
id
name
}
}
}
The pattern — loop in JS
async function fetchAllProjects(spaceId: string) {
const all: Array<{ id: string; name: string | null }> = [];
let after: string | null = null;
do {
const data = await gql(query, { spaceId, typeId: PROJECT_TYPE_ID, after });
all.push(...data.entitiesConnection.nodes);
after = data.entitiesConnection.pageInfo.hasNextPage
? data.entitiesConnection.pageInfo.endCursor
: null;
} while (after);
return all;
}
What the response looks like
{
"data": {
"entitiesConnection": {
"totalCount": 657,
"pageInfo": {
"hasNextPage": true,
"endCursor": "WyJwcmltYXJ5X2tleV9hc2MiLFsiMDEyYjYwNTktNjY5NS00MTlmLWEwMTYtNTkwNzQ2ZTVhMjQzIl1d"
},
"nodes": [
{ "id": "00d1d0a8b36b48ae9cb531e09dfbd5be", "name": "AVP" },
{ "id": "012b60596695419fa016590746e5a243", "name": "ONNX Runtime" }
]
}
}
}
The endCursor is opaque base64 — don't parse it, just pass it back as after on the next request.
Loading interactive query runner…
Defaults & limits
| Argument | Default | Practical max |
|---|---|---|
first | varies | ~5000 per request before timeouts; 100-500 is a good page size |
after | null | opaque cursor from previous endCursor |
If you don't pass first, you get the server's default (sometimes only ~10). Always set first explicitly.
When pagination breaks
hasNextPage: falsebuttotalCount> nodes returned: usually means you hit a query timeout server-side. Reducefirstand try again.endCursorreturned asnullwhilehasNextPage: true: a server quirk; treat as end of stream and log it.- Cursor expires: cursors are stateless; they don't expire. But if the underlying data changed dramatically between pages, items can shift between pages or be missed. For consistent reads of large collections, sort by
createdAtoridto lock the order.
Notes
- Most list fields have a
Connectionvariant —entitiesConnection,relationsConnection, etc. The non-connection variants (entities,relations) return a plain array and don't expose pagination. totalCountis computed server-side and may be expensive on large connections. If you don't need it, skip selecting it for faster responses.