SharePoint Framework (SPFx) Complete Guide
Learn SPFx development end to end: project setup, React web parts, PnPjs, Microsoft Graph, REST, extensions, security, App Catalog deployment, and troubleshooting.
- Published
- Reading time
- 25 min read
What you’ll learn
- When should you use SPFx
- SPFx architecture
- SPFx development lifecycle
- Development environment
- Version compatibility
On this page (52 sections)
Direct answer: SharePoint Framework (SPFx) is Microsoft's extensibility model for building client-side solutions that integrate with SharePoint and Microsoft 365. SPFx builds web parts, extensions, custom list and library experiences, Microsoft Graph integrations, SharePoint API integrations, external API integrations, and Teams-integrated experiences where supported — in TypeScript and React, secured by Microsoft Entra ID, and shipped as versioned packages.
- SharePoint and Microsoft 365 — the host: pages, lists, Teams, and workloads.
- SPFx — web parts, extensions, React, PnPjs, SharePoint APIs, Microsoft Graph, external APIs.
This guide teaches the complete lifecycle — understand, set up, build, connect, secure, test, package, deploy, operate, troubleshoot — with current toolchain guidance. For navigation across the topic, use the SPFx hub; for legacy modernization decisions, use Script Editor to SPFx modernization.
When should you use SPFx
Custom development creates maintenance, testing, security, and deployment responsibilities that outlive the build. Route every requirement downward before committing to code:
- Requirement — confirmed with an owner.
- Native Microsoft 365 capability? — yes goes native.
- JSON formatting enough? — presentation-only needs stop here.
- Workflow or automation? — yes evaluates Power Automate.
- Business application? — yes evaluates Power Apps where appropriate.
- Custom SharePoint or Microsoft 365 UI? — yes evaluates SPFx.
SPFx is powerful but justified only where custom development earns its lifetime cost. Compare against Power Apps vs SPFx for the closest boundary.
SPFx architecture
- User — authenticated by Microsoft Entra ID with single sign-on.
- SharePoint Online — pages, lists, and surfaces hosting the solution.
- SPFx component — web part or extension running in user context.
- React and TypeScript — UI layer and type-safe logic.
- Service layer — PnPjs, SharePoint REST, Microsoft Graph, external APIs.
- Microsoft 365 and business systems — data behind the experience.
Identity flows through every layer: Entra ID authenticates the user, SharePoint user permissions bound SharePoint access, and approved API permission grants bound Graph and API access. Later sections verify each layer independently.
SPFx development lifecycle
- Plan — requirement, data, permissions, environments.
- Scaffold — generate the project with current tooling.
- Develop — components, services, and configuration.
- Test — local, personas, error paths.
- Build — compile, bundle, optimize.
- Package — versioned solution package.
- Deploy — App Catalog to sites.
- Approve permissions — administrator review of API scopes.
- Validate — production behavior and access.
- Monitor — errors, usage, dependencies.
- Maintain — versions, upgrades, ownership.
Development does not end when code compiles — packaging, approval, validation, and operations are part of the lifecycle, and this guide treats them as first-class stages.
Development environment
Set up against current Microsoft guidance for the SPFx release being targeted — verified against the official setup documentation at the time of writing, and re-check before starting because these requirements move. The current baseline for recent SPFx releases:
- Node.js — a supported LTS release matching your SPFx version (recent releases target Node.js v22 LTS). Confirm with
node --version; SPFx is only supported on LTS releases. - Package manager — npm, confirmed with
npm --version. - Generator and toolchain — Yeoman plus the SharePoint generator plus the build orchestrator for your SPFx release, installed globally (see the version section below for which orchestrator applies).
- Editor and browser — Visual Studio Code or any client-side-capable editor, plus a modern browser for testing.
- Microsoft 365 developer tenant — required before testing against real SharePoint data; never develop directly against production.
- Operating system — macOS, Windows, or Linux are all supported.
Official reference: Set up your SharePoint Framework development environment on Microsoft Learn.
Version compatibility
SPFx version compatibility matters because the framework, Node.js, TypeScript, React, and the build toolchain move together — mismatched combinations produce failures that look like broken code. The critical fact, verified against current Microsoft documentation:
| SPFx release line | Build toolchain | What changes |
|---|---|---|
| v1.0 through v1.21.x | Legacy gulp-based toolchain | gulp tasks, gulpfile customization, legacy setup guide applies |
| v1.22 and later | Heft-based toolchain (default for new projects) | Heft orchestration, config-driven rig, webpack still bundles underneath |
Older and newer SPFx versions genuinely use different toolchains: commands such as the legacy gulp serve, bundle, and package-solution tasks belong to pre-v1.22 projects and must not be copied into current-version tutorials. If you maintain an older project, follow the legacy gulp-toolchain setup guide for that release line; for new work, follow the Heft-based guidance below. Always confirm the Node.js LTS, TypeScript, and React versions supported by your exact SPFx release before installing anything.
Official references: Heft-based toolchain and the SPFx roadmap update for platform direction.
Create an SPFx project
Create a project directory, then scaffold with the current SharePoint generator — verified against the official Hello World tutorial:
mkdir spfx-documents-webpart
cd spfx-documents-webpart
yo @microsoft/sharepoint
Answer the generator prompts for your goal — for a first web part: component type WebPart, your web part name, and your framework choice (React for the patterns in this guide). The generator creates the scaffolding and installs dependencies, then reports the command to start developing (see the testing section). Key inputs to get right at scaffolding time are the solution name, component type, web part name, and framework selection, because they shape the generated project described next.
Official reference: Build your first SharePoint client-side web part on Microsoft Learn.
Project structure
Know what each generated area does, when developers normally change it, and what to leave alone:
| Path | What it does | Change guidance |
|---|---|---|
src/ | Web parts, components, services, styles, localization | Daily working area — components and services live here |
config/ | Build, bundle, serve, and deployment configuration | Adjust deliberately; understand before editing |
sharepoint/ | Solution packaging inputs | Touch for packaging metadata and assets |
package.json | Dependencies and npm scripts for the toolchain | Add dependencies carefully; use provided scripts |
| TypeScript config | Compiler behavior for the project | Rarely changed outside toolchain upgrades |
| Component manifest | Web part metadata: ID, version, hosts, defaults | Version and metadata intentionally per release |
| Localization files | User-facing strings per language | Externalize strings here, never inline copy |
| Toolchain rig files | Shared build configuration (current toolchain) | Reference, do not fork casually |
Exact filenames vary by SPFx and toolchain release — treat this table as a map of responsibilities, and confirm names against your generated project.
Web part anatomy
A web part class extends the framework base class, declares typed properties, renders a React component into its DOM element, and exposes configuration through the property pane and manifest:
- Web part — class, lifecycle, manifest, deployment identity.
- Properties — typed values authors configure.
- React component — rendering from props and state.
- Service — data access behind an interface.
- SharePoint, Graph, or API — data behind the service.
The base class supplies lifecycle, context, display mode, instance identity, and the DOM element. Your code supplies properties, rendering, and services — nothing else belongs in the web part class.
React in SPFx
Use modern React patterns supported by your SPFx release: functional components, props, state, hooks including useEffect, event handling, loading and error states, and component composition. Never fetch data inside render paths — effects and services own that work:
import * as React from "react";
export interface IDocumentsProps {
title: string;
items: string[];
loading: boolean;
error?: string;
}
export function Documents(props: IDocumentsProps): JSX.Element {
if (props.loading) {
return <p>Loading documents…</p>;
}
if (props.error) {
return <p>Documents are unavailable right now. Try again later.</p>;
}
if (props.items.length === 0) {
return <p>No documents found.</p>;
}
return (
<section>
<h2>{props.title}</h2>
<ul>
{props.items.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</section>
);
}
Props carry data down, state tracks loading and failure, and every branch — loading, error, empty, data — renders deliberately. Match the React version supported by your SPFx release; this guide teaches patterns, not React itself.
TypeScript in SPFx
TypeScript is the primary SPFx language: interfaces and types describe web part properties, service contracts, and API shapes; async and await structure data calls; generics type reusable services where useful; explicit null handling removes whole classes of runtime surprises:
export interface IDocument {
id: number;
title: string;
url: string;
}
Model every service boundary with interfaces like this one — components receive typed data, never raw API payloads.
Fluent UI
Fluent UI supplies Microsoft 365-aligned buttons, inputs, dialogs, panels, and details experiences with an accessibility baseline generic controls lack. Confirm which Fluent UI approach fits the current SPFx ecosystem before adding anything — versions and packages move with SPFx releases, so verify against current guidance rather than copying install commands from older samples. Never stack a second UI framework on top without a reason the design can defend.
Property pane
Configurable properties — title, list, display mode, item counts, feature flags — flow from editor to property pane to web part properties to React component. Define them with the framework's property pane fields, type them in the props interface, and default them in the manifest's properties bag:
import {
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneToggle
} from "@microsoft/sp-property-pane";
export interface IHelloWorldWebPartProps {
description: string;
showWelcome: boolean;
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: { description: "Display settings" },
groups: [
{
groupFields: [
PropertyPaneTextField("description", {
label: "Description"
}),
PropertyPaneToggle("showWelcome", {
label: "Show welcome",
onText: "On",
offText: "Off"
})
]
}
]
}
]
};
}
Property panes are reactive by default — authors see changes as they edit — and every value read in rendering is escaped or validated before display. Confirm field availability against your SPFx release; the shape above follows the long-standing configuration pattern.
SharePoint context
The web part context exposes the current site, web, user, page context, and HTTP and Graph clients. Pass what components need through props and services — never stash context in globals, which couples every component to ambient state and breaks testability. Services receive the pieces they need (a client, a site URL) at construction; components never touch context directly.
Data access architecture
Never scatter direct API calls through UI components. Route every call through a service interface with an implementation per data source:
- React component — renders props and state only.
- Service interface — typed operations the UI depends on.
- Service implementation — PnPjs, REST, Graph, or API calls.
- PnPjs, REST, Graph, or API — the data behind the contract.
This buys testability (mock the interface), maintainability (one place per data concern), reuse across components, centralized error handling, and separation of concerns that survives team changes.
SharePoint REST
REST remains appropriate for SharePoint-specific operations — lists, items, libraries, files — especially where precise control matters. Call it through the framework HTTP client with the standard configuration, select only needed fields, and handle failures through the service layer:
import {
SPHttpClient,
SPHttpClientResponse
} from "@microsoft/sp-http";
export async function getListTitle(
client: SPHttpClient,
siteUrl: string,
listTitle: string
): Promise<string> {
const url =
siteUrl +
"/_api/web/lists/getbytitle('" +
encodeURIComponent(listTitle) +
"')?$select=Title";
const response: SPHttpClientResponse = await client.get(
url,
SPHttpClient.configurations.v1
);
if (!response.ok) {
throw new Error("List request failed with status " + response.status);
}
const data = await response.json();
return data.Title as string;
}
Graph does not automatically replace every SharePoint REST endpoint — list schemas, versioning detail, and fine-grained permission structures frequently still belong on SharePoint-side APIs.
PnPjs
PnPjs wraps supported SharePoint and Graph operations — lists, items, libraries, files, users, groups, search, batching — in a fluent, typed API that removes most REST boilerplate. Initialize it with the web part context so calls run as the current user, and align the PnPjs major version with the targeted SPFx release:
import { spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import type { WebPartContext } from "@microsoft/sp-webpart-base";
export interface IListItem {
id: number;
title: string;
}
export async function getItems(
context: WebPartContext,
listTitle: string
): Promise<IListItem[]> {
const sp = spfi().using(SPFx(context));
try {
const items = await sp.web.lists
.getByTitle(listTitle)
.items.select("Id", "Title")();
return items.map((item) => ({ id: item.Id, title: item.Title }));
} catch (error) {
throw new Error(
"Could not read list. Confirm it exists and the user can access it."
);
}
}
Request only necessary fields, batch independent reads, and keep every call behind the service interface. Verify current package names against official PnP documentation before implementing.
Microsoft Graph
Graph fits users, groups, Teams, OneDrive files, and Microsoft 365 services reached from SPFx through the Graph client — under delegated permissions a tenant administrator approves, following least privilege, with 401 and 403 handled distinctly:
import type { WebPartContext } from "@microsoft/sp-webpart-base";
import type { MSGraphClientV3 } from "@microsoft/sp-http";
export async function getMyDisplayName(
context: WebPartContext
): Promise<string> {
const client: MSGraphClientV3 =
await context.msGraphClientFactory.getClient("3");
try {
const me = await client.api("/me").select("displayName").get();
return me.displayName as string;
} catch (error) {
throw new Error(
"Could not read the current user. Confirm Graph permission approval."
);
}
}
Request least-privilege scopes, obtain admin consent where required, and never assume automatic access to all Microsoft 365 data. Verify the client pattern against current documentation for your SPFx release. Concepts: Microsoft Graph for beginners and what Microsoft Graph is.
SharePoint REST versus PnPjs versus Graph
| Technology | Best fit | Strengths | Considerations |
|---|---|---|---|
| SharePoint REST | SharePoint-specific operations | Precise control, no abstraction | Verbose; manual batching and typing |
| PnPjs | Developer convenience over supported APIs | Fluent, typed, batteries included | Version alignment with the SPFx release |
| Microsoft Graph | Cross-Microsoft 365 data | One surface, delegated permissions | Not every SharePoint operation is exposed |
Real solutions routinely combine two or all three — Graph for people and files, PnPjs or REST for list internals. The operation decides, never habit.
External API integration
Enterprise APIs enter through Microsoft Entra authentication against secured endpoints, with a backend mediation layer wherever the API cannot authenticate the user directly. SPFx runs in the browser, so it can never embed client secrets, passwords, privileged API keys, or long-lived sensitive credentials — bundles are downloadable by design. The documented client for Entra-secured APIs applies here; verify its current guidance for your SPFx release before implementing, and move any secret-bearing call behind the mediated backend.
- SPFx — user-context request.
- Microsoft Entra ID — identity without embedded secrets.
- Protected API — authorized endpoint.
- Business system — data under proper authorization.
CORS
Browser origin rules cause CORS failures when the API has not allowed the SharePoint origin: preflight rejections and blocked responses are server-configuration facts, not SPFx bugs. Never suggest disabling security controls as a workaround — fix allowed origins on the API side or route through a secure backend. When direct browser calls cannot be authorized cleanly, mediation is the architecture, not a fallback.
Authentication versus authorization
Authentication answers who the user or application is; authorization answers what it may do. The chain runs user, SPFx, token, API, authorization — and Microsoft Entra ID underpins identity while each API enforces its own access rules. Debugging starts by naming which link failed: sign-in and consent problems are authentication; denials for a signed-in user are authorization.
- User — authenticated with single sign-on.
- SPFx — acquires tokens for declared resources.
- Token — scoped identity proof, never a secret to log.
- API — validates token and scope.
- Authorization — grants or denies the operation.
API permissions
Protected calls need approved permission grants: declare least-privilege scopes in the solution, submit them for tenant administrator review, and treat approval as a deployment gate — unapproved permissions fail at runtime, not at build time. Verify the current approval workflow before documenting UI steps, since admin center experiences evolve; the invariant is request, review, approve, then runtime access.
- SPFx solution — declares required scopes.
- Permission request — visible to reviewers.
- Tenant admin review — least privilege scrutinized.
- Approved permission — recorded per solution version.
- Runtime access — succeeds under the grant.
SharePoint user permissions versus API permissions
SharePoint permissions control the user's SharePoint access; API permissions control application and API access — and a Graph grant never gives the current user unrestricted access to everything. Behavior follows the API pattern in use: delegated user-context calls stay bounded by what the user may touch, which is why effective-access testing with real personas remains mandatory. Confusing the two layers is the most common authorization misunderstanding in SPFx work.
SPFx extensions
Extensions customize the experience around content: Application Customizers for page-level scenarios, ListView Command Sets for row commands, and Field Customizers for column rendering. Each deploys as a package through the App Catalog with the same permission model as web parts. Keep this section as orientation — one practical scenario per type below, with dedicated deep-dives tracked as future content.
Application Customizer
Appropriate for supported application-level UI scenarios such as headers, footers, banners, and page behavior through supported placeholders. Never present it as a replacement for arbitrary master-page manipulation — classic chrome hacks do not transfer, and the requirement gets redesigned instead.
- Modern SharePoint — page with supported placeholders.
- SPFx Application Customizer — scoped,reviewed chrome.
- Supported extension experience — survives service updates.
ListView Command Set
Custom commands for supported list and library scenarios: select a document, invoke the custom command, and run the business action or API call. Respect selection context (single versus multiple rows), verify the acting user's permissions before executing, and handle empty or mixed selections explicitly.
- Select document — rows provide context.
- Custom command — validated against selection and access.
- Business action or API — executed with error handling.
Field Customizer
Custom field rendering scenarios belong here when declarative JSON formatting cannot carry the requirement. Compare honestly per column: JSON where presentation suffices, SPFx where supported custom rendering or business logic justifies code. No universal winner — the column decides. Reference: what SPFx extensions are.
State management
Most web parts need only React state, hooks, and context. Avoid adding heavy state libraries for simple component trees — prop drilling two levels deep does not justify a store. Complex multi-view applications may require more architecture, decided per solution rather than by habit. Keep this section deliberately short: state shape follows the service contracts already defined.
Configuration without hard-coding
Tenant URLs, site URLs, list IDs, API endpoints, and environment values never belong inline. Prefer web part properties for author-configured values, configuration modules for solution constants, and environment-specific build and deployment configuration for per-stage differences — with secrets handled server-side, never in the bundle. Configuration is not secret storage: anything shipped in a browser bundle is visible to the user by definition.
Error handling
Apply one reusable model to every data call: request, loading, success renders; failure classifies, logs, and ends in a useful user message. Cover 401, 403, 404, throttling responses where relevant, server errors, network failure, and invalid configuration distinctly — each has a different owner and fix. Never expose sensitive server responses to end users; escape or validate everything rendered from properties and APIs.
- Request — through the service layer with loading state.
- Loading — skeleton or placeholder, never a blank hole.
- Success — renders typed data.
- Failure — classified by cause.
- Log — diagnostics without secrets or personal data.
- Useful user message — actionable next step, not internals.
Logging
Log operation, context, error category, and correlation information where available — enough to reproduce failures from reports alone. Never log access tokens, secrets, or sensitive personal and business data beyond need. No proprietary logging framework is prescribed here; consistency within the solution matters more than the library chosen.
Performance
Minimize unnecessary API calls, select only required fields, filter server-side where possible, paginate, batch, cache where appropriate, lazy-load secondary experiences, manage bundle size, review dependencies, render React efficiently, never load huge lists into browser memory, and design loading states. No fabricated benchmarks are published — measure each solution against its own baseline and fix what the measurements indict.
SharePoint large data
Never assume all list or library data can load client-side. Design filtering, index-aware queries where applicable, pagination, search-backed retrieval where appropriate, server-side APIs, and data virtualization where appropriate into the architecture from the start. No exact platform limits are hard-coded here — verify current values against Microsoft documentation when sizing, and design so limits constrain gracefully instead of failing loudly.
Security checklist
Accessibility
Semantic HTML, keyboard navigation, focus management, accessible labels, ARIA where appropriate, screen-reader behavior, contrast, and accessible components are implementation quality — not a final optional step. Prefer Fluent UI or native controls with built-in accessibility behavior over custom widgets that reimplement it badly.
Local development and testing
Run and preview with the current supported workflow: start the local development server from the project (which serves the local bundles and opens the hosted workbench), trusting the developer certificate once per workstation as current setup guidance describes. The hosted workbench loads local code against real tenant data — which means tenant data access, permissions, and configuration affect every test, and development assumptions must be re-verified in shared environments. Never present outdated local-workbench behavior as current; confirm the workflow against the documentation linked in the environment section.
Testing strategy
Test components, service layers, APIs, permissions, personas, error paths, configuration, and production-like conditions. Where permissions matter, exercise owner, member, and visitor or restricted personas — testing only as an administrator hides the failures users will find. Error paths and misconfiguration deserve first-class tests: denied access, missing lists, and wrong environments are normal production events, not edge cases.
Build for production
Production builds compile TypeScript, bundle and optimize assets, and prepare package artifacts through the toolchain supported by the targeted SPFx release — invoked through the project's npm scripts, never through legacy gulp tasks on current-toolchain projects. Understand conceptually what the build does even when the commands are one-liners: type-checking, bundling, minification, manifest generation, and artifact staging each catch different defect classes.
Solution package
The SharePoint solution package is the versioned distribution unit: solution metadata, features where relevant, API permission requests, and version identity traveling together. Understand what the package contains conceptually — metadata, manifests, bundles, and permission declarations — without memorizing generated internals that the toolchain owns.
App Catalog
The tenant App Catalog distributes packages organization-wide; site-collection catalogs scope distribution where currently supported and appropriate. Choose per governance needs: broad reuse favors the tenant catalog, isolated or sensitive solutions favor scoping. Verify current Microsoft guidance before stating catalog capabilities, then follow the lifecycle: developer builds, package created, catalog upload, deployment, SharePoint site availability.
- Developer — builds and versions the package.
- Build — production artifacts prepared.
- Solution package — versioned distribution unit.
- App Catalog — upload to tenant or scoped catalog.
- Deployment — solution enabled per governance.
- SharePoint site — component available to authors.
- SPFx component — running for real users.
Deployment lifecycle
Build, package, upload, deploy, approve API permissions, add or enable the solution, then validate in the target — with exact steps varying by solution type and current Microsoft behavior. Uploading a package alone never proves successful deployment; validation in the target with real personas closes the loop.
Solution versioning
Production solutions need version discipline: package versions that map to source control, release notes describing behavior change, deployment history per environment, rollback planning before rollout, and environment promotion in order. No mandatory semantic-versioning policy is invented here — but unversioned or unreleasable solutions are not production-grade regardless of convention chosen.
Dev, test, and production
Promote through source control into dev, test, then production, with URLs, list IDs, API endpoints, permissions, app registrations, and configuration differing per stage. Nothing environment-specific is embedded in code — configuration resolves per environment, and each stage validates the resolution before promotion.
- Source control — single truth for code and config templates.
- Dev — developer velocity with realistic data.
- Test — production-like permissions and configuration.
- Production — validated releases only.
CI and CD
Keep the pipeline conceptual and small: pull request with lint and tests, build, package, artifact, approval, deploy. GitHub Actions and Azure DevOps both express this shape; no dedicated CI article exists on nextM365 yet, so this guide stays at pipeline shape rather than a full tutorial. The invariant is gating: unreviewed code never reaches the catalog, and unvalidated packages never reach production.
- Pull request — review with automated checks.
- Lint and test — fast feedback before build.
- Build — production artifacts.
- Package — versioned distribution unit.
- Artifact — stored, traceable, promotable.
- Approval — human gate with permission review.
- Deploy — staged rollout with validation.
Production readiness checklist
Code: TypeScript clean; errors handled; no unnecessary dependencies; no hard-coded environment values.
Security: no secrets; least privilege; API permissions reviewed; authorization tested.
UX: loading, empty, and error states; accessibility reviewed.
Performance: API calls, data volume, bundle, and caching strategy reviewed.
Deployment: package versioned; App Catalog plan defined; permissions documented; rollback considered.
Operations: logging strategy, ownership, documentation, and support path defined.
Troubleshooting hub
| Symptom | Check | Likely cause category | Next step |
|---|---|---|---|
| Project does not build | SPFx, Node, and toolchain versions | Version mismatch | Align to the supported combination for the release |
| Node or toolchain compatibility error | LTS status and release support matrix | Unsupported runtime | Install the supported LTS for the SPFx release |
| Module not found | Install state, package names, imports | Dependencies or drifted APIs | Reinstall, verify names against current docs |
| Web part not appearing | Deployment scope, app installation, hosts | Incomplete deployment chain | Complete catalog, deploy, and add steps |
| Package not available | Catalog upload and deployment state | Distribution gap | Confirm upload, deployment, and scope |
| Solution not deployed | Catalog state versus site state | Missing enable step | Add or enable the solution where designed |
| Graph 401 | Sign-in, consent, token acquisition | Authentication | Fix identity and consent before code changes |
| Graph 403 | Requested versus approved scopes | Authorization | Request least privilege and obtain approval |
| API permission missing | Package declaration versus admin state | Approval gap | Request and obtain administrator approval |
| PnPjs request failing | Context init, select clauses, batching | Call construction | Reproduce as raw REST to isolate the layer |
| SharePoint REST 403 | Effective user access, request shape | Authorization or malformed call | Test as the user, then inspect the request |
| External API CORS | Allowed origins, mediation layer | Server configuration | Fix server-side or add mediated backend |
| Authenticated client 401 or 403 | Token resource, scopes, consent | Identity or grant gap | Verify resource, scopes, and approval state |
| Environment URL incorrect | Configuration per environment | Hard-coded or stale values | Externalize and verify per environment |
| Works in dev, not production | Config, URLs, approvals, versions | Environment drift | Diff environments systematically |
| Dependency or version conflict | Duplicate frameworks, lockfile drift | Dependency hygiene | Dedupe, align, and re-verify the build |
Each row is triage, not a tutorial — deeper fix guides are tracked as future content. Related patterns: SPFx troubleshooting.
Common SPFx mistakes
| Mistake | Corrective direction |
|---|---|
| Using SPFx when native functionality suffices | Route requirements through the decision framework first. |
| Copying legacy JavaScript directly into SPFx | Extract requirements and redesign; evidence, not design. |
| Direct API calls throughout UI components | Introduce a service layer behind interfaces. |
| Hard-coded URLs | Externalize to properties and environment configuration. |
| Secrets in browser code | Move to a secured backend; redesign the integration. |
| Over-requesting Graph permissions | Least privilege, justified per scope. |
| Loading entire large lists | Filter, paginate, and virtualize by design. |
| Ignoring 401, 403, and throttling handling | Classify failures with distinct handling per cause. |
| Ignoring accessibility | Design keyboard, focus, and screen-reader behavior up front. |
| Ignoring production logging | Log operations with correlation, never secrets. |
| Using outdated dependencies | Align with the targeted SPFx release and re-verify. |
| Ignoring Node and SPFx compatibility | Match the supported combination before installing. |
| Testing only as an administrator | Exercise owner, member, and restricted personas. |
| Skipping production validation | Validate in the target with real users before sign-off. |
Migration and modernization bridge
SPFx is particularly relevant when migration discovers custom functionality that cannot be retained or replaced with simpler modern capabilities. Route classic findings through assessment into business requirements, then native, JSON, Power Platform, or SPFx onto modern SharePoint — with depth in Classic SharePoint to Modern SharePoint, Script Editor to SPFx modernization, and the migration hub.
- Classic SharePoint — custom functionality as found.
- Migration assessment — inventory with requirements.
- Legacy customization — classified per component.
- Business requirement — defended by an owner.
- Native, JSON, Power Platform, or SPFx — simplest fitting architecture.
- Modern SharePoint — rebuilt, secured, validated.
From Script Editor to SPFx
Modernizing legacy scripts? The companion guide routes each script through requirement analysis instead of automatic porting: Script Editor to SPFx modernization — including the decision tree this guide builds on.
Solution blueprint: enterprise SPFx application
Reference shape only — not a customer implementation. A user reaches SharePoint Online, where SPFx renders React UI backed by a service layer reaching SharePoint through PnPjs, Microsoft 365 through Graph, and business systems through a secure API — all under Microsoft Entra ID, surrounded by permissions, logging, configuration, error handling, and performance discipline.
- User — authenticated with single sign-on.
- SharePoint Online — host surfaces.
- SPFx — web parts and extensions.
- React — components from props and state.
- Service layer — PnPjs to SharePoint, Graph to Microsoft 365, secure API to business systems.
- Microsoft Entra ID — identity beneath every call.
Developer learning path
- SPFx fundamentals — model, lifecycle, and this guide with what SPFx is.
- Web parts — anatomy, properties, and rendering above.
- React — components, hooks, and states above.
- SharePoint data — REST shapes and service design above.
- PnPjs — service-layer patterns above.
- Microsoft Graph — delegated access with Graph for beginners.
- Extensions — surfaces and scenarios above with what extensions are.
- Authentication — identity and permission layers above.
- Deployment — packaging, catalog, and approval above.
- Production engineering — security, performance, logging, and operations above.
Each stage links only to genuinely existing pages — dedicated deep-dives are tracked as future content, not placeholder links.
Building a complex SPFx solution
If you are working through SharePoint modernization, Microsoft Graph, external APIs, authentication, deployment, or complex SPFx architecture, share the technical challenge with nextM365: Discuss Your SPFx Project.
Continue with Explore SPFx, planning SharePoint modernization, Script Editor to SPFx modernization, and the SPFx roadmap update.
Related resources
Topics covered
React · Project Structure · Permissions · ALM · Security
Frequently asked questions
What is SPFx?
The SharePoint Framework is Microsoft’s client-side extensibility model for building web parts, extensions, and Microsoft 365 integrations with TypeScript and React. Solutions run in the browser in the current user’s context and deploy as versioned packages through the SharePoint App Catalog.
What can you build with SPFx?
Custom web parts, page and list extensions, field customizers, command sets, Graph-connected experiences, SharePoint data solutions, external API integrations, and Teams-integrated experiences where applicable.
When should SPFx be used?
When a confirmed requirement needs custom SharePoint or Microsoft 365 UI and no native capability, JSON formatting, Power Automate, or Power Apps approach fits. Custom development creates maintenance, testing, security, and deployment responsibilities.
Does SPFx require React?
No — web parts can use any framework or none — but React is the standard, best-supported UI layer, and current guidance and samples assume it unless a project has a specific reason to differ.
Can SPFx use PnPjs?
Yes. PnPjs simplifies supported SharePoint and Graph operations from an SPFx service layer. Align the PnPjs major version with the targeted SPFx release and verify current package names against official PnP documentation.
Can SPFx call Microsoft Graph?
Yes, through the Graph client with delegated permissions approved by a tenant administrator. Request least-privilege scopes, never assume automatic access, and handle 401 and 403 distinctly.
Can SPFx call external APIs?
Yes, through Microsoft Entra authentication against secured endpoints, adding a backend mediation layer where the API cannot authenticate the user directly. Never embed secrets in the browser bundle.
How does authentication work in SPFx?
Solutions run as the signed-in user with automatic single sign-on. Authentication identifies the user; separate authorization layers — SharePoint user permissions and approved API permission grants — decide what is allowed.
Can secrets be stored in SPFx?
No. Bundles are downloadable by design, so client secrets, passwords, and privileged keys belong in a secured backend or managed-identity flow that the solution calls.
What is an SPFx Extension?
A customization of the experience around content rather than a page component: Application Customizers for page-level scenarios, ListView Command Sets for row commands, and Field Customizers for column rendering. All deploy as packages through the App Catalog.
How is an SPFx solution deployed?
Build and bundle with the toolchain supported by the targeted SPFx release, create the versioned solution package, upload it to the tenant or site-collection App Catalog, deploy it, obtain tenant administrator approval for requested API permissions, add or enable the solution, and validate in the target.
What is the SharePoint App Catalog?
The tenant or site-collection library that distributes solution packages to SharePoint. Uploading a package makes it available; deployment, permission approval, and adding the solution to sites are separate steps.
How do you troubleshoot SPFx 403 errors?
Separate authentication (401) from authorization (403): confirm sign-in and consent, compare requested versus approved scopes, verify the user’s effective SharePoint access, and check environment configuration — fixing identity and approval first, code last.
Sources
Have a Microsoft 365 topic idea?
Share article suggestions, community session ideas, corrections, or real-world scenarios for future nextM365 learning notes.
Keep learning Microsoft 365
Explore more practical tutorials for SharePoint, Power Platform, Copilot Studio, migration, automation, governance, and security.
Continue learning
Related tutorials