Four ways to update a term in the SharePoint Term Store programmatically — SharePoint’s own REST API, Microsoft Graph, plain JavaScript, and PnPjs — and what actually differs between them beyond “which one is easiest.”
In this post: Option 1: SharePoint REST API · Option 2: Microsoft Graph · Option 3: plain JavaScript · Option 4: PnPjs · Which one should you actually use? · When would you actually use this? · Related reading
Option 1: SharePoint REST API
SharePoint’s own termStore REST endpoint works directly against your tenant, no other Microsoft 365 service involved:
fetch("https://yourtenant.sharepoint.com/sites/yoursite/_api/v2.1/termStore/groups/{groupId}/sets/{setId}/terms/{termId}", {
method: "PATCH",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer your_access_token"
},
body: JSON.stringify({
"labels": [{ "name": "Updated Term Name", "languageTag": "en-US" }]
})
})
.then(response => response.json())
.then(data => console.log("Updated successfully", data))
.catch(error => console.error("Error updating term store", error));
Direct and dependency-free, but you’re handling OAuth/MSAL token acquisition yourself, and the auth setup is SharePoint-specific — it won’t carry over if you’re also touching other Microsoft 365 services in the same project.
Option 2: Microsoft Graph
Same operation through Graph’s unified endpoint instead:
fetch("https://graph.microsoft.com/v1.0/sites/{siteId}/termStore/sets/{setId}/terms/{termId}", {
method: "PATCH",
headers: {
"Authorization": "Bearer your_access_token",
"Content-Type": "application/json"
},
body: JSON.stringify({
"labels": [{ "name": "Updated Term Name", "languageTag": "en-US" }]
})
})
.then(response => response.json())
.then(data => console.log("Updated successfully", data))
.catch(error => console.error("Error updating term store", error));
Worth it specifically if the same app is already touching Outlook, Teams, or other Graph-covered services — one auth model instead of a separate one per API. Not worth switching to just for this one operation if SharePoint REST already works for the rest of your project.
Option 3: plain JavaScript
Functionally the same as Option 1, wrapped in an async function for cleaner error handling — useful if you want this as a reusable utility rather than an inline call:
async function updateTerm(termId, groupId, setId, accessToken) {
const requestUrl = `https://yourtenant.sharepoint.com/sites/yoursite/_api/v2.1/termStore/groups/${groupId}/sets/${setId}/terms/${termId}`;
const headers = new Headers({
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`
});
const body = JSON.stringify({
"labels": [{ "name": "Updated Term Name", "languageTag": "en-US" }]
});
try {
const response = await fetch(requestUrl, { method: "PATCH", headers, body });
const data = await response.json();
console.log("Updated successfully", data);
return data;
} catch (error) {
console.error("Error updating term store", error);
throw error;
}
}
Option 4: PnPjs
PnPjs’s taxonomy module wraps term store access behind a typed, promise-based API instead of hand-built REST calls. Reading term store data is well-documented and stable:
import { spfi } from "@pnp/sp";
import "@pnp/sp/taxonomy";
const sp = spfi(/* your configured instance */);
// Get term store info, then navigate down to a set
const termStoreInfo = await sp.termStore();
const termSet = sp.termStore.groups.getById(groupId).sets.getById(setId);
const terms = await termSet.getAllTerms();
Worth flagging directly rather than guessing: PnPjs’s taxonomy module is explicitly called out in PnP’s own docs as newer and still evolving compared to the rest of the library, and update/write operations on terms aren’t as consistently documented as the read side shown above. If you’re relying on PnPjs specifically to write term updates in production, check the current PnPjs taxonomy documentation for the exact method signature rather than assuming it matches an older example — this is one corner of the library where copying a two-year-old snippet is more likely to be wrong than usual.
Which one should you actually use?
| Approach | Ease of use | Dependencies | Best for |
|---|---|---|---|
| SharePoint REST API | Medium | None | SharePoint-only projects, no other M365 integration |
| Microsoft Graph | Medium | Graph permissions in Entra ID | Projects already touching other M365 services |
| Plain JavaScript | Hard | None | A reusable utility function, no framework |
| PnPjs | Easy (reads); check docs (writes) | PnPjs library | Larger SPFx projects already using PnPjs elsewhere |
Microsoft Graph is worth it specifically if the same app is already touching other Microsoft 365 services — not worth switching to for this one operation alone.
When would you actually use this?
- A term set’s labels need to change in bulk (a naming convention update, a rebrand) — scripting it beats editing terms one at a time in the admin center.
- You’re building an SPFx web part that already uses PnPjs elsewhere in the project — staying consistent with one library beats mixing in raw REST calls for just this one feature.
- You’re integrating term store updates into a larger Microsoft 365 automation that also touches Teams or Outlook — that’s when Graph’s unified auth model actually pays off.
Related reading
- SharePoint Metadata: What You Need to Know — the broader picture of how metadata, content types, and the Term Store fit together.
- SharePoint Metadata Naming Convention — worth reading before you set up a term set, since internal names lock in at creation the same way column names do.
That covers all four approaches. Questions about your specific setup? Drop them in the comments.
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


