KEEP LEARNING
Build the bigger picture.
The Workflow Engineer connects individual n8n concepts to testing, deployment and running a complete workflow.
Tips > Building Workflows
Most APIs return paginated results -- 100 records per page with a cursor or offset to fetch the next page.
Most APIs return paginated results with a cursor or offset for the next page. For cursor-based or non-standard schemes that the HTTP Request node's built-in pagination cannot express, use a Loop node with explicit cursor tracking: store results and the offset in workflow static data, and branch to a loop or done output based on the total count.
Most APIs return paginated results -- 100 records per page with a cursor or offset to fetch the next page. n8n's Loop node (or the built-in pagination in the HTTP Request node) handles this, but the built-in pagination only covers simple cases. For cursor-based pagination or APIs with non-standard pagination schemes, use a Loop node with explicit cursor tracking.
Real-world example: You need to fetch all issues from a Jira project. The API returns 50 results per page with a startAt offset and a total count.
Trigger
|
Loop Node (loop until all pages fetched)
| |
| +-> HTTP Request: Jira API (current page)
| |
| +-> Code Node: Check if more pages
| | (outputs: "loop" back to Loop, or "done" to exit)
| |
| +-> [loop output connects back to Loop Node]
|
Code Node: Combine All Pages
|
[downstream processing]
const staticData = $getWorkflowStaticData("node");
// Initialize on first iteration
if (!staticData.allResults) {
staticData.allResults = [];
staticData.startAt = 0;
}
const response = $input.first().json;
const pageSize = 50;
// Accumulate results
staticData.allResults.push(...response.issues);
staticData.startAt += pageSize;
// Check if there are more pages
if (staticData.startAt < response.total) {
// More pages -- output to "loop" branch with next offset
return [
[{
json: {
startAt: staticData.startAt,
maxResults: pageSize
}
}],
[] // empty "done" branch
];
} else {
// All pages fetched -- output to "done" branch
const allResults = staticData.allResults;
// Clean up static data
delete staticData.allResults;
delete staticData.startAt;
return [
[], // empty "loop" branch
allResults.map(issue => ({ json: issue }))
];
}
URL: https://your-org.atlassian.net/rest/api/3/search
Method: GET
Query Parameters:
jql: project = "MYPROJ" ORDER BY created DESC
startAt: {{ $json.startAt ?? 0 }}
maxResults: 50
fields: summary,status,assignee,priority,created
This pattern guarantees you fetch all records regardless of the total count, handles APIs that return thousands of results, and keeps memory usage manageable by processing page by page.
Tip: HTTP Request Built-In Pagination
For simple offset-based or header-link pagination, the HTTP Request node has a built-in Pagination option under the settings. Set it to "Offset" with the parameter name and increment. This handles the loop automatically without a Loop node. Use the manual loop approach only when the built-in pagination cannot express your API's pagination scheme.
Related: Use Path Parameters in Webhook URLs for Dynamic Routing · Use Edit Fields in "Map Each" Mode for Simple Renames
KEEP LEARNING
The Workflow Engineer connects individual n8n concepts to testing, deployment and running a complete workflow.
APPLY IT TO YOUR SYSTEM
Bring the process, the tools involved and an example of where the current workflow gets stuck.