How to Use first and after for Pagination in GraphQL
In GraphQL, use the
first argument to specify how many items to fetch, and the after argument to indicate the cursor after which to start fetching. This combination enables cursor-based pagination, allowing clients to load data in chunks efficiently.Syntax
The first argument defines the number of items to return from the list. The after argument takes a cursor string that marks the position after which to start fetching items.
These arguments are typically used together in a query field that returns a Connection type, which includes edges and pageInfo for pagination details.
graphql
query GetItems($first: Int!, $after: String) {
items(first: $first, after: $after) {
edges {
node {
id
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}Example
This example fetches the first 3 items from a list, then uses the endCursor from the response to fetch the next 3 items starting after that cursor.
graphql
query FetchFirst3Items {
items(first: 3) {
edges {
node {
id
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}
# Suppose the response's pageInfo.endCursor is "cursor3"
query FetchNext3Items {
items(first: 3, after: "cursor3") {
edges {
node {
id
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}Output
{
"data": {
"items": {
"edges": [
{"node": {"id": "1", "name": "Item 1"}, "cursor": "cursor1"},
{"node": {"id": "2", "name": "Item 2"}, "cursor": "cursor2"},
{"node": {"id": "3", "name": "Item 3"}, "cursor": "cursor3"}
],
"pageInfo": {
"endCursor": "cursor3",
"hasNextPage": true
}
}
}
}
{
"data": {
"items": {
"edges": [
{"node": {"id": "4", "name": "Item 4"}, "cursor": "cursor4"},
{"node": {"id": "5", "name": "Item 5"}, "cursor": "cursor5"},
{"node": {"id": "6", "name": "Item 6"}, "cursor": "cursor6"}
],
"pageInfo": {
"endCursor": "cursor6",
"hasNextPage": false
}
}
}
}
Common Pitfalls
- Not using the
aftercursor correctly causes repeated data or missing items. - Using
firstwithoutafteralways fetches from the start, ignoring pagination. - Assuming
afteris an offset number instead of a cursor string leads to errors. - Not checking
hasNextPagecan cause unnecessary requests when no more data exists.
graphql
query WrongPagination {
items(first: 3, after: "3") { # Incorrect: '3' is not a cursor
edges {
node {
id
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}
# Correct usage:
query CorrectPagination {
items(first: 3, after: "cursor3") {
edges {
node {
id
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}Quick Reference
| Argument | Description | Type |
|---|---|---|
| first | Number of items to fetch | Int! |
| after | Cursor after which to start fetching | String |
| edges | List of items with cursors | Array |
| pageInfo.endCursor | Cursor for last item in current page | String |
| pageInfo.hasNextPage | Indicates if more pages exist | Boolean |
Key Takeaways
Use
first to limit how many items you get in one request.Use
after with a cursor to fetch the next page of results.Always check
pageInfo.hasNextPage to know if more data is available.The
after value must be a cursor string, not a numeric offset.Combine
first and after for smooth cursor-based pagination.