Cursor-based pagination in GraphQL - Time & Space Complexity
When using cursor-based pagination in GraphQL, we want to know how the time to get results changes as the data grows.
We ask: How does fetching pages with cursors scale with more data?
Analyze the time complexity of the following code snippet.
query GetItems($first: Int, $after: String) {
items(first: $first, after: $after) {
edges {
node {
id
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}
This query fetches a page of items after a given cursor, returning a limited number of results.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Retrieving and returning a fixed number of items (page size) after the cursor.
- How many times: The server scans or accesses items starting from the cursor position, up to the page size.
Explain the growth pattern intuitively.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 items fetched |
| 100 | About 10 items fetched |
| 1000 | About 10 items fetched |
Pattern observation: The work grows linearly with the page size, not the total data size.
Time Complexity: O(k)
This means the time depends mainly on the number of items requested per page, not the total number of items in the database.
[X] Wrong: "Fetching a page with a cursor takes time proportional to the total number of items in the database."
[OK] Correct: Cursor-based pagination fetches only a limited number of items after the cursor, so time depends on page size, not total data size.
Understanding cursor-based pagination time helps you explain efficient data fetching in real apps, showing you know how to handle large lists smoothly.
"What if the cursor is not indexed and the server must scan from the start each time? How would the time complexity change?"
Practice
Solution
Step 1: Understand pagination purpose
Pagination is used to split large data into smaller parts for easier handling.Step 2: Identify cursor role
Cursor marks the position in the data to fetch the next part without overlap or missing items.Final Answer:
To fetch data in small parts using a cursor to mark position -> Option CQuick Check:
Cursor-based pagination = fetch data in parts [OK]
- Thinking pagination fetches all data at once
- Confusing cursor with sorting
- Assuming pagination deletes data
Solution
Step 1: Recall GraphQL cursor pagination syntax
The standard usesfirstto limit items andafterto specify the cursor.Step 2: Match options with correct syntax
{ items(first: 5, after: "cursor123") { edges { node } } }usesfirstandaftercorrectly; others use incorrect argument names.Final Answer:
{ items(first: 5, after: "cursor123") { edges { node } } } -> Option DQuick Check:
Use first and after arguments [OK]
- Using limit instead of first
- Using startAfter or afterCursor which are invalid
- Confusing argument names
{ users(first: 3, after: "YXJyYXljb25uZWN0aW9uOjE=") { edges { node { id name } } pageInfo { hasNextPage endCursor } } }What does the
endCursor represent in the result?Solution
Step 1: Understand pageInfo fields
endCursormarks the cursor of the last item returned in the current page.Step 2: Differentiate from other fields
hasNextPageshows if more pages exist;endCursoris not a count or first item cursor.Final Answer:
The cursor of the last item in the current page -> Option AQuick Check:
endCursor = last item cursor [OK]
- Confusing endCursor with total count
- Thinking endCursor is first item cursor
- Assuming endCursor is page count
{ posts(first: 10, afterCursor: "abc123") { edges { node { title } } } }Why does this query fail?
Solution
Step 1: Check argument names for cursor pagination
The correct argument to specify the cursor isafter, notafterCursor.Step 2: Validate other parts
firstaccepts a number;edgesis valid; cursor values are strings.Final Answer:
The argument should be namedafter, notafterCursor-> Option AQuick Check:
Use 'after' argument name [OK]
- Using incorrect argument names
- Thinking first must be string
- Misunderstanding edges field usage
{ comments(first: 4) { edges { node { id text } } pageInfo { hasNextPage endCursor } } }To fetch the next batch, which query should you use?
Solution
Step 1: Understand how to continue pagination
Use theafterargument with theendCursorvalue from the previous page to fetch the next batch.Step 2: Check argument correctness
first: 4limits to 4 items;aftermoves cursor forward;beforeorlastare for backward pagination.Final Answer:
{ comments(first: 4, after: "endCursor_value") { edges { node { id text } } pageInfo { hasNextPage endCursor } } } -> Option BQuick Check:
Use first and after with endCursor for next batch [OK]
- Using before instead of after for next page
- Using last instead of first for forward pagination
- Using limit instead of first argument
Ready to prove it?
Pass the test and this pattern moves unknown
