Deploy an SPFx solution to the app catalog
Run npm run build: with SPFx 1.24, Heft writes the .sppkg file to sharepoint/solution. Upload it to the tenant app catalog or a site collection app catalog, then select Enable app. Have the API permissions approved on the API access page. To ship an update, increment the version and upload the package again.
Before you start
- An SPFx 1.24 project generated with the Yeoman generator and the Heft toolchain.
- Node.js 26 LTS (or 22 / 24) installed on the build machine.
- The SharePoint Administrator role, or an administrator account for the target site collection app catalog.
- To approve Microsoft Graph permissions: a Global Administrator.
Step 1: Check the project toolchain
Since SPFx 1.22, new projects use Heft instead of gulp. With SPFx 1.24, released on October 28, 2026, the gulp toolchain is no longer supported.
Open package.json and read the scripts. A standard 1.24 project defines build as heft test --clean --production && heft package-solution --production.
A project still on 1.21 or earlier uses gulp bundle --ship followed by gulp package-solution --ship. With Heft, the --ship option becomes --production.
# Show the npm scripts defined in the project
npm pkg get scriptsCheck: The build script calls heft, not gulp.
Step 2: Configure package-solution.json
The config/package-solution.json file describes the package. The solution.version field uses the four-part format 1.0.0.0.
includeClientSideAssets: true bundles the JavaScript and CSS into the .sppkg. SharePoint then serves them from the app catalog, or from the Office 365 CDN if it is enabled.
skipFeatureDeployment: true allows tenant-wide deployment. The administrator can then select "Enable this app and add it to all sites". In that case, Feature Framework definitions (lists, fields) are ignored.
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "my-webpart-client-side-solution",
"id": "<solution GUID>",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false
},
"paths": {
"zippedPackage": "solution/my-webpart.sppkg"
}
}Check: The file contains a stable id, a version and the intended value for skipFeatureDeployment.
Step 3: Declare API permissions
If the solution calls Microsoft Graph or an API secured with Entra ID, add webApiPermissionRequests to the solution object.
Add one entry per resource / scope pair. The resource value is the display name of the Entra ID application, not its objectId: an objectId causes an error at approval time.
Deployment creates pending requests. Whether they are approved or not, the solution can still be deployed: the code must never assume that access has been granted.
"webApiPermissionRequests": [
{ "resource": "Microsoft Graph", "scope": "Calendars.Read" },
{ "resource": "Microsoft Graph", "scope": "User.ReadBasic.All" }
]Check: Each required scope has its own entry.
Step 4: Build the production package
Stop the local server (heft start), then run the build. The script runs the tests, compiles in production mode and packages the solution.
The .sppkg is written to sharepoint/solution, with the name set in paths.zippedPackage. The raw contents are visible in sharepoint/solution/debug.
npm run build
# Explicit equivalent described in the Microsoft tutorial
npx heft build --production
npx heft package-solution --production
ls sharepoint/solution/*.sppkgCheck: A freshly timestamped .sppkg file exists in sharepoint/solution.
Step 5: Choose the app catalog: tenant or site collection
The tenant app catalog makes the solution installable in every site collection. Open it from the SharePoint admin center: More features, then Open under Apps.
A site collection app catalog limits the solution to that site only. An administrator enables it with Add-SPOSiteCollectionAppCatalog, Add-PnPSiteCollectionAppCatalog or m365 spo site appcatalog add. A tenant app catalog must already exist.
In a site collection app catalog, the "add to all sites" option only makes the solution available within that site collection.
Connect-SPOService -Url https://contoso-admin.sharepoint.com
Add-SPOSiteCollectionAppCatalog -Site https://contoso.sharepoint.com/sites/marketingCheck: The "Apps for SharePoint" library appears in the target site, or the Manage apps page opens for the tenant.
Step 6: Upload and enable the solution
On the Manage apps page, select Upload and choose the .sppkg. The Enable app panel opens.
If skipFeatureDeployment is true, select "Enable this app and add it to all sites" for a tenant-wide deployment. Otherwise, each site owner adds it through Add an app.
From the command line, the CLI for Microsoft 365 separates adding and deploying. PnP PowerShell does both with Add-PnPApp -Publish.
m365 login
m365 spo app add --filePath ./sharepoint/solution/my-webpart.sppkg --overwrite
m365 spo app deploy --name my-webpart.sppkg --skipFeatureDeployment
# PnP PowerShell equivalent
# Add-PnPApp -Path ./sharepoint/solution/my-webpart.sppkg -Overwrite -Publish -SkipFeatureDeploymentCheck: The "App Package Error Message" column is empty and the component appears in a page's toolbox.
Step 7: Approve API permissions
Open the API access page in the SharePoint admin center. Select each pending request, then Approve.
Delegated permissions are granted to the "SharePoint Online Client Extensibility Web Application Principal". They apply to every SPFx solution in the tenant, not only to the one that requested them.
Microsoft Graph requires a Global Administrator. For a third-party API registered in the tenant, the Application Administrator role is enough.
m365 spo serviceprincipal permissionrequest list
m365 spo serviceprincipal permissionrequest approve --id <request-id>
m365 spo serviceprincipal grant listCheck: The request moves to the approved requests list and the API call responds without a 403 error.
Step 8: Ship a new version
Increment solution.version in package-solution.json (for example from 1.0.0.0 to 1.1.0.0), keep the same id, rebuild, then upload the .sppkg again, replacing the existing one.
For a tenant-wide solution, the new package updates every instance. For a solution installed site by site, apply the update with m365 spo app upgrade or Update-PnPApp.
If the solution provisions assets through the Feature Framework, also increment the feature version and declare upgradeActions.
npm run build
m365 spo app add --filePath ./sharepoint/solution/my-webpart.sppkg --overwrite
m365 spo app deploy --name my-webpart.sppkg
m365 spo app upgrade --id <app-id> --siteUrl https://contoso.sharepoint.com/sites/marketingCheck: The app catalog shows the new version number and the page loads the new files.
Common errors
- After moving to SPFx 1.24,
gulp bundle --shipfails or no longer exists. - The gulp toolchain is no longer supported in 1.24. Migrate the project to Heft, CI commands included, and use
--productioninstead of--ship. - The API request cannot be approved and shows an error about the resource.
- Set
resourceto the display name of the Entra ID application, not its objectId, then redeploy the package. - Duplicates appear in the Tenant Wide Extensions list after an extension update.
- Do not select "add to all sites" again during an update: this option is only for the initial activation of extensions.
- The list or field defined in the solution is not created.
- With
skipFeatureDeployment: true, Feature Framework definitions are ignored. Set the value tofalseand install the solution site by site.
Sources
- Microsoft Learn — Heft-based SPFx toolchain (opens in a new tab)
- Microsoft Learn — SPFx roadmap (version 1.24) (opens in a new tab)
- Microsoft Learn — SPFx 1.22 release notes (opens in a new tab)
- Microsoft Learn — Deploy your web part to a SharePoint page (opens in a new tab)
- Microsoft Learn — Tenant-scoped solution deployment (opens in a new tab)
- Microsoft Learn — Site collection app catalog (opens in a new tab)
- Microsoft Learn — Manage apps using the Apps site (opens in a new tab)
- Microsoft Learn — Connect to Entra ID-secured APIs (opens in a new tab)
- Microsoft Learn — Manage access to APIs (API access page) (opens in a new tab)
- Microsoft Learn — Provision SharePoint assets and upgradeActions (opens in a new tab)
- CLI for Microsoft 365 — spo app add (opens in a new tab)
- CLI for Microsoft 365 — spo app deploy (opens in a new tab)
- CLI for Microsoft 365 — spo app upgrade (opens in a new tab)
- PnP PowerShell — Add-PnPApp (opens in a new tab)
- PnP PowerShell — Update-PnPApp (opens in a new tab)