The error Module '"@pnp/sp/presets/all"' has no exported member 'sp' means your code is PnPjs v2, but npm installed v3 or v4. Those versions dropped the global sp object. Create your own instance with spfi() instead:
// Old (PnPjs v2) - fails on v3/v4 with TS2305
// import { sp } from "@pnp/sp/presets/all";
// sp.setup({ spfxContext: this.context });
// New (PnPjs v3/v4)
import { spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
const sp = spfi().using(SPFx(this.context));
const items = await sp.web.lists.getByTitle("SPGDemo Products").items();
That returns the list items as plain JSON. No sp.setup(), no .get().
In this tutorial, we’ll reproduce the Module ‘”@pnp/sp/presets/all”‘ has no exported member ‘sp’ error in a real SPFx project, fix it with getSP(), and cover the TS2307 “Cannot find module” variants too.
| Tested with | Version |
|---|---|
| SharePoint Framework | 1.23.2 (Heft toolchain) |
| Node.js | 22 LTS |
| React | 17.0.1 |
| PnPjs | @pnp/sp and @pnp/logging 4.22.0 |
What the TS2305 error looks like
I pasted classic v2 code into a fresh SPFx 1.23.2 web part (scaffolded as in the SPFx setup with Heft). VS Code underlined sp right away and listed both errors in the Problems panel:
Module '"@pnp/sp/presets/all"' has no exported member 'sp'. ts(2305)
Module '"@pnp/sp"' has no exported member 'sp'. ts(2305)

The web part file had the old setup in onInit:
import { sp } from "@pnp/sp/presets/all";
protected async onInit(): Promise<void> {
await super.onInit();
sp.setup({ spfxContext: this.context });
}
npm run build stops at the TypeScript step with the same two errors:
Encountered 2 errors
[build:typescript] src/webparts/pnpProducts/PnpProductsWebPart.ts:9:10 - (TS2305) Module '"@pnp/sp/presets/all"' has no exported member 'sp'.
[build:typescript] src/webparts/pnpProducts/services/ProductService.ts:1:10 - (TS2305) Module '"@pnp/sp"' has no exported member 'sp'.

Why does @pnp/sp have no exported member ‘sp’?
PnPjs v3 moved away from the global sp and graph objects and doesn’t export one at all. You build an instance with spfi() and attach behaviors like SPFx(this.context). v4 kept that model.
@pnp/sp/presets/all still exists in 4.22.0. I checked its type file: it attaches every module and re-exports types like IWeb, but nothing named sp. So changing the path to "@pnp/sp" just gives you the second TS2305.
Downgrading to v2 isn’t a real fix on SPFx 1.23. It’s the code that needs to change, the same way moving from gulp to Heft changed the build commands.
Fix it with spfi() and a getSP() helper
1. Install the packages. Microsoft Learn’s PnPjs guide installs @pnp/sp plus @pnp/logging, which is no longer a peer dependency. Run this in the project folder:
npm install @pnp/sp@4.22.0 @pnp/logging@4.22.0 --save-exact
npm ls @pnp/sp
2. Add a config file at src/webparts/pnpProducts/pnpjsConfig.ts. It creates the instance once and holds your selective imports:
import { WebPartContext } from "@microsoft/sp-webpart-base";
import { spfi, SPFI, SPFx } from "@pnp/sp";
import { LogLevel, PnPLogging } from "@pnp/logging";
// Selective imports: attach only the parts of PnPjs this solution uses
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
let _sp: SPFI | undefined = undefined;
export const getSP = (context?: WebPartContext): SPFI => {
if (context !== undefined) {
// Runs once, from onInit: binds PnPjs to the web part's context
_sp = spfi().using(SPFx(context)).using(PnPLogging(LogLevel.Warning));
}
if (_sp === undefined) {
throw new Error("Call getSP(this.context) in onInit before using PnPjs.");
}
return _sp;
};

@pnp/sp/webs, /lists and /items attach exactly what sp.web.lists.getByTitle().items needs. Forget one and you’ll get a “property does not exist” error instead.
3. Call it from onInit in src/webparts/pnpProducts/PnpProductsWebPart.ts. This line replaces sp.setup():
import * as React from "react";
import * as ReactDom from "react-dom";
import { Version } from "@microsoft/sp-core-library";
import { type IPropertyPaneConfiguration, PropertyPaneTextField } from "@microsoft/sp-property-pane";
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
import PnpProducts from "./components/PnpProducts";
import { IPnpProductsProps } from "./components/IPnpProductsProps";
import { getSP } from "./pnpjsConfig";
import { ProductService } from "./services/ProductService";
export interface IPnpProductsWebPartProps {
listTitle: string;
}
export default class PnpProductsWebPart extends BaseClientSideWebPart<IPnpProductsWebPartProps> {
protected async onInit(): Promise<void> {
await super.onInit();
getSP(this.context); // replaces the old sp.setup({ spfxContext: this.context })
}
public render(): void {
const element: React.ReactElement<IPnpProductsProps> = React.createElement(PnpProducts, {
service: new ProductService(this.properties.listTitle),
listTitle: this.properties.listTitle
});
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse("1.0");
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: { description: "Read a SharePoint list with PnPjs v4" },
groups: [
{
groupName: "Settings",
groupFields: [PropertyPaneTextField("listTitle", { label: "List title" })]
}
]
}
]
};
}
}
4. Use it in a service. The model goes in src/webparts/pnpProducts/models/IProduct.ts:
export interface IProduct {
Id: number;
Title: string;
Modified: string;
}
And the data class in src/webparts/pnpProducts/services/ProductService.ts. Note the call ends in (), not .get():
import { SPFI } from "@pnp/sp";
import { getSP } from "../pnpjsConfig";
import { IProduct } from "../models/IProduct";
export class ProductService {
private readonly _sp: SPFI;
constructor(private readonly _listTitle: string) {
this._sp = getSP(); // the instance created in onInit
}
public async getWebTitle(): Promise<string> {
const web = await this._sp.web.select("Title")();
return web.Title;
}
public async getProducts(): Promise<IProduct[]> {
return this._sp.web.lists
.getByTitle(this._listTitle)
.items.select("Id", "Title", "Modified")
.orderBy("Title")();
}
}
5. Render the results. Props in src/webparts/pnpProducts/components/IPnpProductsProps.ts:
import { ProductService } from "../services/ProductService";
export interface IPnpProductsProps {
service: ProductService;
listTitle: string;
}
The component, src/webparts/pnpProducts/components/PnpProducts.tsx, loads both calls and shows a Fluent UI spinner or error bar:
import * as React from "react";
import { MessageBar, MessageBarType, Spinner } from "@fluentui/react";
import styles from "./PnpProducts.module.scss";
import { IPnpProductsProps } from "./IPnpProductsProps";
import { IProduct } from "../models/IProduct";
const PnpProducts: React.FC<IPnpProductsProps> = ({ service, listTitle }) => {
const [webTitle, setWebTitle] = React.useState<string>("");
const [products, setProducts] = React.useState<IProduct[] | undefined>(undefined);
const [error, setError] = React.useState<string>("");
React.useEffect(() => {
Promise.all([service.getWebTitle(), service.getProducts()])
.then(([title, items]) => {
setWebTitle(title);
setProducts(items);
})
.catch((err: Error) => setError(err.message));
}, [service, listTitle]);
if (error) {
return <MessageBar messageBarType={MessageBarType.error}>{error}</MessageBar>;
}
if (!products) {
return <Spinner label={`Loading ${listTitle}...`} />;
}
return (
<section className={styles.pnpProducts}>
<h2>{listTitle}</h2>
<p>Site: {webTitle} - {products.length} items read with PnPjs v4 (spfi + SPFx)</p>
<table className={styles.table}>
<thead>
<tr><th>ID</th><th>Product</th><th>Modified</th></tr>
</thead>
<tbody>
{products.map((p) => (
<tr key={p.Id}>
<td>{p.Id}</td>
<td>{p.Title}</td>
<td>{new Date(p.Modified).toLocaleDateString("en-US")}</td>
</tr>
))}
</tbody>
</table>
</section>
);
};
export default PnpProducts;
Styles go in PnpProducts.module.scss. For a richer grid, see displaying list items with a DetailsList:
.pnpProducts {
color: var(--bodyText);
h2 {
margin: 0 0 4px;
}
.table {
border-collapse: collapse;
width: 100%;
th,
td {
border-bottom: 1px solid #edebe9;
padding: 8px 12px;
text-align: left;
}
th {
background: #f3f2f1;
}
}
}
In the manifest I set the toolbox title and the default list:
"title": { "default": "SPG PnPjs Products" },
"officeFabricIconFontName": "ProductList",
"properties": {
"listTitle": "SPGDemo Products"
}
Test the fix in the SharePoint workbench
Point config/serve.json at your site’s workbench, replacing {tenantDomain} with your tenant:
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
"port": 4321,
"https": true,
"initialPage": "https://{tenantDomain}/sites/SPGuides/_layouts/workbench.aspx"
}
Then start the dev server in the VS Code terminal. It compiles with zero errors and opens the workbench:
heft start

Click Load debug scripts, hover the canvas, click + and pick SPG PnPjs Products. On my SPGuides site it read all four products:

The hosted workbench retires on 12/01/2026. After that, add the debug query string heft start prints to any modern page instead.
Stop the server with Ctrl+C and build the package. This time it finishes and writes spg-pnpjs-imports.sppkg:
npm run build

Upload the .sppkg to the app catalog when you’re ready, as in your first SPFx web part.
Error TS2307: Cannot find module ‘@pnp/sp/presets/all’
TS2307 is a different problem: TypeScript can’t find the package at all. I reproduced it by running the v2 code with the @pnp/sp folder missing from node_modules:
[build:typescript] Error: src/webparts/pnpProducts/PnpProductsWebPart.ts:9:20 - (TS2307) Cannot find module '@pnp/sp/presets/all' or its corresponding type declarations.
[build:typescript] Error: src/webparts/pnpProducts/services/ProductService.ts:1:20 - (TS2307) Cannot find module '@pnp/sp' or its corresponding type declarations.
That happens after cloning a project without running npm install, or when @pnp/sp isn’t in package.json. Run the install command above, then fix the imports.
The same error with other packages is covered in cannot find module jquery in SPFx and cannot find module sp-build-web.
v3 imports that break on PnPjs v4
Code already on v3 can still fail after upgrading to v4. I left a v3 import of @pnp/sp/items/get-all in the fixed project. TypeScript passed, since it doesn’t check side-effect imports, but webpack failed:
[build:webpack] Error: ... lib/webparts/pnpProducts/pnpjsConfig.js:7:0 - Module not found: Error: Can't resolve '@pnp/sp/items/get-all' in '...\lib\webparts\pnpProducts'
v4 removed get-all. Page through big lists with the async iterator instead:
// v4 replacement for items.getAll(): async iterator paging
const all: IProduct[] = [];
for await (const page of sp.web.lists.getByTitle("SPGDemo Products").items.top(500)) {
all.push(...page);
}
Two more v4 changes: taxonomy moved to @pnp/graph, and add() returns the new item directly, so drop .data. For filtering, see filtering list items in SPFx with PnPjs.
Common problems and fixes
- Property ‘lists’ does not exist: add the matching selective import, like
import "@pnp/sp/lists";, in pnpjsConfig.ts. - Errors stay red after the fix: run “TypeScript: Restart TS Server” from the VS Code command palette.
- Extra tsconfig warnings in Problems: VS Code’s newer TypeScript flags
moduleResolution node10andtarget ES5.npm run builduses the project’s 5.8 and ignores them. - Calls fail at runtime: call
getSP(this.context)aftersuper.onInit(), not inside event handlers.
More PnPjs patterns, like binding list items to a Fluent UI dropdown, use the same getSP() setup. Ready-made projects are on our Power Platform and SPFx solutions page.
A few more SPFx guides you might want next:
Frequently Asked Questions
Why does @pnp/sp/presets/all have no exported member ‘sp’?
Since PnPjs v3 there’s no global sp object. The preset still exists but only attaches modules and re-exports types. Create an instance with spfi().using(SPFx(this.context)) instead.
What replaces sp.setup({ spfxContext: this.context })?
Call spfi().using(SPFx(this.context)) once in onInit, usually through a getSP() helper in pnpjsConfig.ts, as the Microsoft Learn PnPjs guide shows.
What does error TS2307 mean in SPFx?
TypeScript can’t find the module or its type declarations. Usually the package isn’t installed: run npm install @pnp/sp @pnp/logging, then check package.json.
Should I still use @pnp/sp/presets/all?
It works in v4, but the PnPjs selective imports docs say presets aren’t recommended in client-side solutions. Import only webs, lists and items.
Can I downgrade to PnPjs v2 to keep my old code?
Not on current SPFx. v2 is out of support and was built for older TypeScript and gulp. Updating the imports takes a few minutes, as shown above.

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.