Understanding the differences between SharePoint REST API and PnPjs with practical TypeScript examples.
👋 Introduction
If you've worked with SharePoint Framework (SPFx), you've probably come across two popular ways of communicating with SharePoint data:
- SharePoint REST API
- PnPjs (Patterns and Practices JavaScript Library)
Both approaches allow developers to interact with SharePoint lists, libraries, sites and other resources.
But here's a question I often think about:
If both can perform the same operations, why should we use PnPjs when we can directly call SharePoint REST APIs?
Let's understand the differences with practical examples.
🔍 1. What is SharePoint REST API?
SharePoint REST API allows developers to interact with SharePoint resources using HTTP requests.
You can perform CRUD operations:
- 🟢 Create items
- 🔵 Read items
- 🟡 Update items
- 🔴 Delete items
SharePoint exposes REST endpoints using the /_api/ path.
For example, to retrieve items from a SharePoint list:
GET https://yourtenant.sharepoint.com/sites/dev/_api/web/lists/getbytitle('Employees')/items
You can use standard HTTP methods and OData query options such as $select, $filter, $expand and $orderby.
Example: Fetch list items using REST API
In SPFx, we can use the built-in SPHttpClient to make SharePoint REST requests.
import { SPHttpClient } from '@microsoft/sp-http';
const webUrl = this.context.pageContext.web.absoluteUrl;
const endpoint =
`${webUrl}/_api/web/lists/getbytitle('Employees')/items` +
`?$select=Id,Title,Department`;
const response = await this.context.spHttpClient.get(
endpoint,
SPHttpClient.configurations.v1,
{
headers: {
Accept: 'application/json;odata=nometadata'
}
}
);
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const result = await response.json();
console.log(result.value);
That's it! We're directly communicating with the SharePoint REST endpoint.
🧩 2. What is PnPjs?
PnPjs is an open-source JavaScript and TypeScript library developed by the SharePoint Patterns and Practices community.
It provides a fluent API for working with SharePoint and Microsoft 365 REST APIs.
Instead of manually constructing HTTP requests, headers and endpoint URLs for every operation, PnPjs provides a cleaner and more developer-friendly approach.
Some useful features include:
- ✨ Fluent API syntax
- 🔐 SPFx context integration
- 📦 TypeScript-friendly development
- ⚡ Request batching
- 🚀 Caching capabilities
- 🔗 SharePoint and Microsoft Graph integrations
Example: Fetch list items using PnPjs
First, install the package:
npm install @pnp/sp
Then configure PnPjs with your SPFx context.
Create a file called PnPConfig.ts:
import { SPFI, spfi } from "@pnp/sp";
import { SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
let sp: SPFI;
export const initializePnP = (context: any): void => {
sp = spfi().using(SPFx(context));
};
export const getSP = (): SPFI => {
if (!sp) {
throw new Error("PnPjs has not been initialized");
}
return sp;
};
Initialize it in your SPFx web part:
import { initializePnP } from "./PnPConfig";
public async onInit(): Promise<void> {
await super.onInit();
initializePnP(this.context);
}
Now let's retrieve the same list items:
import { getSP } from "./PnPConfig";
const items = await getSP()
.web
.lists
.getByTitle("Employees")
.items
.select("Id", "Title", "Department")();
console.log(items);
Notice the difference?
We don't need to manually construct the REST endpoint or parse the response using response.json().
PnPjs provides a fluent interface that makes the code easier to read and maintain.
⚖️ 3. REST API vs PnPjs: Side-by-Side Comparison
| Feature | SharePoint REST | PnPjs |
|---|---|---|
| Approach | Direct HTTP requests | Fluent library API |
| Syntax | Endpoint + HTTP methods | Method chaining |
| Configuration | Request and headers | Library configuration |
| TypeScript | Manual typing often needed | Type-friendly API |
| CRUD operations | Supported | Supported |
| Filtering | OData query strings | Fluent query methods |
| Batching | REST batch requests | Batch helpers |
| Dependencies | SPFx HTTP client | Additional packages |
| Flexibility | Direct endpoint control | Convenient abstractions |
Important: PnPjs is not a separate SharePoint API. It is a library that helps developers consume SharePoint and Microsoft 365 APIs.
Under the hood, PnPjs uses REST requests for its SharePoint operations.
💻 4. Let's Compare a Few More Operations
Let's look at how the syntax differs when performing everyday SharePoint operations.
A. Retrieve items with filtering
REST API
GET /_api/web/lists/getbytitle('Employees')/items?$filter=Department eq 'IT'
PnPjs
const items = await getSP()
.web
.lists
.getByTitle("Employees")
.items
.filter("Department eq 'IT'")();
B. Create a new list item
REST API
const endpoint =
`${webUrl}/_api/web/lists/getbytitle('Employees')/items`;
const response = await this.context.spHttpClient.post(
endpoint,
SPHttpClient.configurations.v1,
{
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata"
},
body: JSON.stringify({
Title: "John",
Department: "IT"
})
}
);
PnPjs
const result = await getSP()
.web
.lists
.getByTitle("Employees")
.items
.add({
Title: "John",
Department: "IT"
});
C. Update an existing item
PnPjs
await getSP()
.web
.lists
.getByTitle("Employees")
.items
.getById(1)
.update({
Title: "John Updated"
});
D. Delete an item
PnPjs
await getSP()
.web
.lists
.getByTitle("Employees")
.items
.getById(1)
.delete();
For REST API, you would send the appropriate HTTP request to the specific item endpoint with the required headers and request configuration.
🤔 5. Which One Should You Choose?
This is where things get interesting.
There isn't one universal answer. It depends on your project requirements.
Choose SharePoint REST API when:
- You need direct control over HTTP requests.
- You're working with a specific REST endpoint.
- You want to avoid an additional library dependency.
- You're integrating SharePoint with applications outside SPFx.
- You need to understand exactly what request is being sent.
Choose PnPjs when:
- You're developing SPFx web parts or extensions.
- You frequently perform CRUD operations.
- You want cleaner and more readable TypeScript code.
- You're working with multiple SharePoint lists.
- You want to use fluent queries, batching and caching features.
🚀 6. My Take as an SPFx Developer
When working on SharePoint solutions, I find that code readability and maintainability become increasingly important as projects grow.
Imagine working with multiple lists, attachments, user information, lookup fields and complex filtering conditions.
Writing every request manually can make your service layer lengthy and repetitive.
PnPjs provides a convenient abstraction for these operations.
However, I wouldn't say that REST API is outdated or that developers should stop learning it.
Understanding SharePoint REST API is important even when you're using PnPjs.
Why?
Because knowing what's happening behind the scenes helps you troubleshoot errors, understand OData queries, optimize requests and debug complex SharePoint operations.
My recommendation:
- Learn SharePoint REST API fundamentals first.
- Use PnPjs to simplify common SPFx development tasks.
- Understand both approaches so you can choose the right one for each scenario.
🎯 Conclusion
SharePoint REST API and PnPjs are both valuable tools in the SharePoint development ecosystem.
REST API gives you direct access and control over HTTP requests, while PnPjs provides a fluent and convenient way to interact with SharePoint and Microsoft 365.
Rather than treating them as competitors, understand how they complement each other.
Learn the API. Understand the abstraction. Write better code. 🚀
📚 Useful Resources
- Microsoft Learn – Connect to SharePoint APIs in SPFx
- Microsoft Learn – Use PnPjs with SPFx
- PnPjs Official Documentation
- SharePoint REST API Documentation
💬 What do you prefer in your SPFx projects: SharePoint REST API or PnPjs?
Share your experience in the comments. I'd love to hear how other developers approach this!



Top comments (0)