Skip to content

Supporting a new SPFx version — maintainer-only

Process for adding a new spfxVersion target. Formats are harvested from official npm packages, not docs or memory — verify byte-level. See Microsoft docs: SPFx compatibility and Release 1.23.

Source of truth

Single file packages/core/src/versions.ts:13 (SPFX_VERSIONS, SPFX_DEFAULT_TARGET, SPFX_TARGETS, spfxNpmVersion()). All consumers derive from it: config default, CLI prompts/validation, rspfx doctor, scaffold pins. Adding a target is one entry. Current matrix → compatibility.md#spfx-version-matrix.

Detect a new release

SignalWhere
npm dist-tagsnpm dist-tag ls @microsoft/generator-sharepoint (@latest=GA, @next=preview)
Release notesSPFx releases — replace 1.23 with target version (1.22, 1.21, …)
Repogithub.com/SharePoint/spfx (open since 1.23)

Wait for GA. Preview risks drifting scaffold pins.

Release notes — what matters

SignalImpact
New component type (e.g. Copilot Apps)New manifest shape, possibly new packaging elements
Schema changesCheck SPFx schemas and write-manifests schema
Deprecations (e.g. 1.23 workbench)Dev URL, not bundle format
Toolchain shift (Heft since 1.23)Official scaffold shape, not RSPFx format

Harvest (core methodology)

  1. In scratch dir npm pack the official packages at target version: @microsoft/spfx-heft-plugins, @microsoft/sp-build-web, @microsoft/sp-webpart-base, and all @microsoft/sp-* runtimes.
  2. Extract: component IDs/version/preloadComponents from node_modules/@microsoft/sp-*/dist/*.manifest.json; formats (manifest builder, AMD wrapper, manifests.js, .sppkg layout, workbench URL) from build plugins.
  3. Record provenance in reference/FORMATS.md per section (exact versions harvested).
  4. On discrepancy verify against an unzipped official .sppkg before changing code.

Diff & update references

Compare IDs, manifest schema, bundle wrapper, manifests.js, .sppkg layout, package-solution.json semantics vs current. Update reference/FORMATS.md, reference/sp-component-ids.json, and its compiled copy packages/manifest-generator/src/data/component-ids.ts in sync.

Add version

ts
{ target: '1.24', npmVersion: '1.24.0', toolchain: 'heft', status: 'ga' }

Fields: target (user-facing), npmVersion (scaffold pin), toolchain (informational), status (ga/preview). Downstream updates are automatic.

Tests & docs

Tests: core default assertion, template dep pins, CLI new/config flag values. Then bun run typecheck && bun run test.

Docs to update:

FileWhat
compatibility.mdVersion matrix
commands.md--spfx-version flag
why-not-to-migrate.mdSupported row
ARCHITECTURE.mdNon-negotiables if formats changed

History lives only in CHANGELOG.md.

Verify

  1. rspfx new --spfx-version <v> --yes && rspfx package
  2. Bundle header starts with capture line then define('<id>_<version>', …)
  3. Diff .sppkg entry list vs harvested reference
  4. Real-tenant install (app catalog → site → workbench)
  5. Blackbox parity: bun run test -- --run packages/sppkg-builder/tests/blackbox (fast, RSPFx invariants only) or OFFICIAL_SPPKG_TEST=1 bun run test -- --run packages/sppkg-builder/tests/blackbox with OFFICIAL_SPPKG_VERSIONS=1.22,1.23,1.24 for full RSPFx vs official ZIP comparison (see packages/sppkg-builder/tests/blackbox.test.ts:1 and bench/blackbox-compare.mjs:1). The harness treats both generators as external ZIP producers and normalizes volatile AppPartConfig Id/Extension Instance Id before asserting AppManifest.xml, [Content_Types].xml, feature_*.xml, <featureId>/*_*.xml, and entry-list equality.

Checklist

Gotchas

GotchaDetail
Never re-publish yanked versionnpm E400 after unpublish — bump instead
examples/* stay on 1.22Intentional matrix coverage, don't "fix"
Workbench retiring Dec 1 2026Debug Toolbar replaces it — affects dev URLs
Harvest from spfx-cli repo when freshestSince 1.23 it's open source

Tip: after harvest, unzip an official .sppkg and byte-compare define('<id>_<version>' header and zip entry order — visual diff misses layout bugs.

Released under the MIT License.