Worth leading with directly, since it changes what this post can actually recommend: `.getAll()` was removed entirely in PnPjs v4, the current major version as of 2026. The replacement isn’t a renamed method — it’s a genuinely different pattern, the same async-iterator (`for await…of`) approach covered from the JavaScript-fundamentals side in Does “for…of” loop wait for async awaits in JavaScript?. This post covers the current v4 pattern, plus `.getAll()` for anyone still maintaining a v3 project.
In this post: The current way: async iteration · Collecting everything into one array · If you’re still on v3: .getAll() still works · Reducing the payload with select and filter · Handling a page fetch that fails mid-loop · When would you actually use this? · Related reading
The current way: async iteration
A list’s items collection in PnPjs v4 is itself an async iterable — `for await…of` walks through it page by page, without a separate `.getAll()` call at all:
import { spfi } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
async function logAllItems(sp) {
for await (const page of sp.web.lists.getByTitle("MyList").items.top(1000)) {
console.log(`Got a page of ${page.length} items`);
}
}
`.top(1000)` sets the page size — there’s no built-in default the way `.getAll()` used to have one (2000), so it needs setting explicitly. Each iteration of the loop hands back one page’s worth of items, not the whole dataset at once; PnPjs makes the next network request automatically as the loop continues, the same lazy-pagination behavior `.getAll()` had internally, just exposed through a standard JavaScript iteration pattern instead of a library-specific method.
.getAll() doesn’t exist in PnPjs v4 — the items collection is an async iterable now, and for await…of replaces it entirely, not as an alternative but as the only current option.
Collecting everything into one array
For code that genuinely needs everything as one flat array — the direct replacement for what `.getAll()` used to return — accumulate across the loop:
async function getAllItems(sp, listName) {
const allItems = [];
for await (const page of sp.web.lists.getByTitle(listName).items.top(1000)) {
allItems.push(...page);
}
return allItems;
}
Worth pausing on before defaulting to this pattern everywhere: collecting everything into memory before doing anything with it defeats part of the point of paginated iteration in the first place. If the actual goal is processing each item (writing it somewhere, transforming it, checking a condition), doing that work directly inside the `for await` loop — page by page — keeps memory usage bounded to one page at a time, rather than the full list size, which matters genuinely once a list is large enough that pagination was needed to begin with.
If you’re still on v3: .getAll() still works
A project still on PnPjs v3 keeps `.getAll()` working — it wasn’t retroactively pulled from existing versions, only dropped starting with v4. Worth knowing the v3-current syntax if that’s genuinely still the version in use (not the older `sp` singleton import from v2, which is a separate, further-outdated pattern):
import { spfi } from "@pnp/sp";
import "@pnp/sp/items";
async function getAllItemsV3(sp, listName) {
return await sp.web.lists.getByTitle(listName).items.getAll(2000); // requestSize, default 2000
}
Worth planning the migration deliberately rather than indefinitely: since v4 removed the method entirely rather than deprecating it with a warning, upgrading a v3 project to v4 later means this specific call site needs rewriting to the iterator pattern above at that point — not a drop-in version bump.
Reducing the payload with select and filter
The same query-narrowing methods apply before iterating, in both versions — worth using them by default rather than pulling every column on every item:
for await (const page of sp.web.lists.getByTitle("MyList").items
.select("Title", "Id")
.filter("Status eq 'Active'")
.top(1000)) {
// process page
}
This matters more with pagination in play than it might on a single small request — a narrower `.select()` genuinely reduces the payload of every single page fetched across the whole iteration, not just one request.
Handling a page fetch that fails mid-loop
Worth wrapping the loop in a try/catch rather than assuming every page fetch succeeds: a page fetch failing partway through — a throttling response, a dropped connection — throws out of the `for await` loop the same way a thrown error would in any other async function, abandoning the remaining pages entirely rather than skipping just the failed one:
const allItems = [];
try {
for await (const page of sp.web.lists.getByTitle("MyList").items.top(1000)) {
allItems.push(...page);
}
} catch (err) {
console.error(`Pagination stopped after ${allItems.length} items:`, err);
// allItems still holds everything successfully retrieved before the failure
}
The partial results collected before the failure are still usable — worth deciding deliberately whether a partial result set is acceptable for the use case, or whether the whole operation needs to be retried from scratch, rather than the failure mode being an unhandled decision made by accident.
When would you actually use this?
- A list genuinely exceeds SharePoint’s 5,000-item view threshold, and a single unindexed query would fail outright — this is exactly the scenario pagination exists for.
- You need to process every item but don’t need them all in memory simultaneously — process inside the `for await` loop rather than accumulating into one array first.
- You’re upgrading a v3 project to v4 — audit for `.getAll()` call sites specifically, since they’ll break at compile/runtime, not just generate a warning.
- The list is comfortably under a few thousand items — plain `.top()`/`.select()` on a single request may not need pagination logic at all; worth checking the actual item count before reaching for either pattern.
Related reading
- Does “for…of” loop wait for async awaits in JavaScript? — the general async-iteration pattern this post’s current PnPjs approach is a real-world application of.
- SharePoint Data Handling with PnP Batching Queries — for bulk writes rather than bulk reads, including the real 100-request batch cap.
The underlying need — paging through a large list without hitting SharePoint’s threshold — hasn’t changed. What changed is the API shape: a library-specific method replaced by a standard JavaScript language feature, which is worth treating as a genuine improvement rather than just a breaking change to work around.
App Catalog Authentication Automation Backup Compliance Content Type CSS Flows Google Javascript Limitations List Metadata MFA Microsoft Node NodeJs O365 OneDrive Permissions PnP PnPJS Policy PowerApps Power Automate PowerAutomate PowerPlatform PowerShell React ReactJs Rest API Rest Endpoint Security Send an HTTP Request to SharePoint SharePoint SharePoint List SharePoint Modern SharePoint Online SPFX SPO Sync Tags Teams Termstore Versioning


