SharePoint Framework (SPFx) Part 3: Deploying Your Web Part With the Microsoft 365 CDN
To ship an SPFx web part, build and package it in production mode (heft build --production then heft package-solution --production on SPFx 1.22 and later, or gulp bundle --ship then gulp package-solution --ship on older projects), and upload the .sppkg to the app catalog. With includeClientSideAssets on, the default, SharePoint hosts the web part's files from the Microsoft 365 CDN if it's enabled, so you don't set a CDN path or copy files by hand.
Published:
Last updated: 2026-10-27
What changed since 2017
The 2017 version of this post set a hardcoded cdnBasePath, ran gulp bundle --ship, and copied the files from temp/deploy into a CDN library by hand. Three things have changed:
| Change | When | Effect |
|---|---|---|
Assets packaged inside the .sppkg (includeClientSideAssets) | SPFx 1.4, late 2017 | SharePoint hosts the files itself. No manual upload, no cdnBasePath. |
| Heft replaces gulp as the build tool | SPFx 1.22 | New commands. Gulp projects still build, with only critical fixes. See SharePoint Framework Toolchain: Heft-based. |
Legacy CDN domain publiccdn.sharepointonline.com retired | Late April 2026 | Hardcoded references return 404. The replacement is public-cdn.sharepointonline.com, but Microsoft's advice is not to hardcode either. See MC1184996. |
publiccdn.sharepointonline.com. If cdnBasePath in config/write-manifests.json uses it, set it back to the placeholder "<!-- PATH TO CDN -->", make sure includeClientSideAssets is true, then rebuild, repackage and redeploy.Before you start
This is part 3. You need a working SPFx web part that runs in the local workbench. If you're starting fresh, follow Microsoft's Build your first SharePoint client-side web part. You also need an app catalog: the tenant app catalog, which a SharePoint Administrator can open from SharePoint admin center > More features > Apps, or a site collection app catalog.
Step 1: Check package-solution.json
Open config/package-solution.json. The settings that matter for deployment:
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-announcements-client-side-solution",
"id": "9af7ce6b-7e38-427b-a4f5-129dd1acfc0a",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false
},
"paths": {
"zippedPackage": "solution/spfx-announcements.sppkg"
}
}
includeClientSideAssets: trueputs the bundles in the package so SharePoint hosts them.skipFeatureDeployment: truelets you make the web part available on every site at once, without installing the app on each site.versionmust go up for every release, or SharePoint won't treat the upload as an update.zippedPackageis where the.sppkgis written, relative to thesharepointfolder.
Microsoft documents every option in SharePoint solution packaging.
Step 2: Turn on the Microsoft 365 public CDN (recommended)
Without the CDN, SharePoint serves your bundles from the app catalog's ClientSideAssets library, which works but is slower for people far from your tenant's data center. With it on, the same files are served from Microsoft's CDN. You do this once per tenant, as a SharePoint Administrator:
Connect-SPOService -Url "https://contoso-admin.sharepoint.com" Get-SPOTenantCdnEnabled -CdnType Public # is it on? Set-SPOTenantCdnEnabled -CdnType Public -Enable $true Get-SPOTenantCdnOrigins -CdnType Public # should include */CLIENTSIDEASSETS
Turning it on creates default origins, including */CLIENTSIDEASSETS, which SPFx needs. If the CDN was turned on before December 2017, or set up without default origins, add it with Add-SPOTenantCdnOrigin -CdnType Public -OriginUrl "*/CLIENTSIDEASSETS". Configuration changes can take up to 15 minutes to apply. See Use the Office 365 CDN with SharePoint Online.
Files in a public origin can be fetched by anyone with the URL, without signing in. That's fine for compiled JavaScript and CSS. Never put keys, secrets or sensitive data in a web part bundle.
Step 3: Build and package for production
SPFx 1.22 and later (Heft)
heft build --clean --production heft package-solution --production
SPFx 1.21 and earlier (gulp)
gulp bundle --ship gulp package-solution --ship
Either way, the package is written to sharepoint/solution/spfx-announcements.sppkg. Without the production flag, the package points at https://localhost:4321, which is what the 2017 post warned about: it only works while your local dev server is running.
Step 4: Deploy to the app catalog
- Open the app catalog's Manage apps page.
- Select Upload, or drag the
.sppkgonto the page. - SharePoint asks you to enable the app. Because
skipFeatureDeploymentistrue, you can choose to make it available to all sites now. Otherwise, site owners add it from Site contents > New > App. - Check the app's row for errors. Problems with the package show there.
To script deployments, use PnP PowerShell:
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/appcatalog" -Interactive -ClientId "<your-app-id>" Add-PnPApp -Path ".\sharepoint\solution\spfx-announcements.sppkg" -Scope Tenant -Publish -SkipFeatureDeployment -Overwrite
For build pipelines, Microsoft's Implement CI/CD using Azure DevOps has both the Heft and gulp versions.
Step 5: Add the web part to a page
- Open a modern page and select Edit.
- Select + where you want the web part and search for its name.
- Add it, configure its properties, and Republish the page.
Then check where it loads from. Open the browser's developer tools, go to the Network tab and reload. The web part's JavaScript should come from public-cdn.sharepointonline.com with the CDN on, or from the app catalog's ClientSideAssets library without it, never from localhost.
Releasing an update
- Increase
versioninpackage-solution.json. - Build and package for production again.
- Upload the new
.sppkgover the old one in the app catalog.
Bundle file names include a hash, so the new files don't overwrite the old ones and pages pick up the new version without stale caches. CDN updates can take up to 15 minutes to reach everyone.
Hosting on your own CDN instead
Some teams host bundles on Azure Storage with Azure Front Door, or another CDN, to share them across tenants or control caching. In that case:
- Set
includeClientSideAssetstofalse. - Set
cdnBasePathinconfig/write-manifests.jsonto your CDN folder. - Build for production, then upload the files from
temp/deployto that folder. - Package and deploy the
.sppkgas above.
Keep previous versions' files on the CDN until no page uses them; Microsoft's team-based development guide explains why deleting them breaks web parts. And don't point cdnBasePath at a SharePoint CDN URL: that's the pattern that broke in April 2026.
Troubleshooting
| Symptom | Likely cause |
|---|---|
Web part loads from localhost:4321 or shows nothing | Packaged without --production or --ship. |
404 errors for publiccdn.sharepointonline.com | Hardcoded legacy CDN path in cdnBasePath or in code. Remove it and redeploy. |
| Web part missing from the toolbox | The app isn't enabled for the site, or the upload has an error in the app catalog. |
| Old version still showing | version wasn't increased, or the CDN is still updating (up to 15 minutes). |
| Bundles fail to load with the CDN on | The */CLIENTSIDEASSETS origin is missing. Check Get-SPOTenantCdnOrigins. |
Replacing old script web parts with SPFx
A common reason to build SPFx web parts is to replace Script Editor and Content Editor web parts, which custom script restrictions in SharePoint Online keep breaking. Before you start, find every page that uses them. SharePoint Essentials Toolkit's free Content search > Text on pages and in web parts searches page text and web part properties, including embedded HTML and script, across many sites, so you know which pages to update.
Frequently asked questions
Do I still need to set cdnBasePath for an SPFx web part?
Not if you use automatic hosting. Since SPFx 1.4, includeClientSideAssets packages the JavaScript and CSS inside the .sppkg, and SharePoint serves them from the Microsoft 365 CDN if it's on, or from the app catalog if not. Set cdnBasePath only when you host the files on your own CDN.
Why does my SPFx web part return 404 for publiccdn.sharepointonline.com?
Microsoft retired the legacy publiccdn.sharepointonline.com domain in April 2026. Anything that hardcodes it, including an SPFx cdnBasePath, now gets 404 errors. Remove the hardcoded path and let SharePoint host the files, or point it at your own CDN. The replacement domain is public-cdn.sharepointonline.com.
What is the difference between Heft and gulp in SPFx?
SPFx 1.22 replaced gulp with Heft as the build tool for new projects. The commands change from gulp bundle --ship and gulp package-solution --ship to heft build --production and heft package-solution --production. Projects on gulp keep working, but get only critical fixes.
Why does my deployed web part try to load from localhost?
The package was built in debug mode. Rebuild and repackage with --production (Heft) or --ship (gulp), then upload the new .sppkg to the app catalog.
Is the Microsoft 365 public CDN safe for my web part files?
Files in a public CDN origin can be fetched by anyone who has the URL, without signing in. That's fine for compiled JavaScript and CSS with no secrets in them. Never put credentials, keys or sensitive data in web part bundles.
Find the pages your new web part replaces
SharePoint Essentials Toolkit Community Edition is free. Search pages and web part properties, inventory sites and find broken links on up to 20 sites per Microsoft 365 tenant. Get your free Community Edition license key.