Scaffolding a new SPFx project fails safe. If your AI agent botches it — wrong component type, wrong framework, a hung terminal — you delete the folder and try again. Nothing was lost, because there was nothing there yet.
An upgrade is a different animal entirely. It runs against a project that already works, with real customizations, real history, and real people depending on it not breaking. Get scaffolding wrong and you waste five minutes. Get an upgrade wrong on a project without a safety net, and you can spend days untangling which of forty changed files broke what.
upgrade.md, the third reference in the SharePoint/spfx-dev-skills skill pack, treats that asymmetry as the whole point. Where create.md (covered in posts 2 and 3) is mostly about replacing interactive prompts with flags, upgrade.md is about procedural discipline — the kind of “measure twice” habits that keep a version bump from turning into an afternoon of git archaeology.
Before You Start: The Clean Git State Precondition
The very first instruction in upgrade.md, before any command runs, is a precondition that has nothing to do with SPFx specifically and everything to do with not losing work:
“Ensure a clean, committed git state. The upgrade rewrites many files; the user needs a clean baseline to review the diff and roll back.”
Read that carefully: the reasoning isn’t “so the upgrade tool works correctly,” it’s “so a human (or an agent) can see exactly what changed and undo it if needed.” If the working tree is dirty when an upgrade is requested, the skill’s instruction is direct — ask the user to commit or stash first. Not “proceed carefully.” Not “back up the changed files individually.” Stop, and get a clean baseline before touching anything.
This is exactly the kind of precondition that pays for itself if you set it up earlier. Post 3 proposed committing immediately after a validated scaffold, specifically because it means this exact requirement is already satisfied by the time an upgrade is ever requested — no separate “please commit your work” conversation needed.
Detecting the Current (and Target) Version
Before running any upgrade command, the skill requires detecting and stating the current version — not assuming it, not guessing from the SPFx release calendar:
- Read
.yo-rc.jsonfor@microsoft/generator-sharepoint.version. - Cross-check the
@microsoft/sp-*package versions inpackage.json. - State the current and target versions before running anything.
That last point matters more than it looks. An agent (or a developer) that silently assumes the target version, without stating what it detected and where it’s headed, is the same failure mode as post 1’s “invents a random package version” problem — just applied to an upgrade instead of a scaffold.
There’s a second check bundled into this step: Node/TypeScript compatibility for the target version. Each SPFx version supports a specific Node range, and if the installed Node version falls outside the target’s range, the build will fail — the skill’s guidance is to surface this up front, using m365 spfx doctor if there’s any uncertainty. This is the same doctor command from post 2, reused here for exactly the reason it exists: catching environment mismatches before they masquerade as mysterious build errors three steps later.
Running the Upgrade
Once the preconditions are satisfied, the actual upgrade runs through the CLI for Microsoft 365, and the command depends on whether a specific target version was requested:
With a specific target version:
m365 spfx project upgrade --toVersion <version> --output md
Upgrading to the latest supported version (no target specified):
m365 spfx project upgrade --output md
--output md produces a human-readable Markdown report of everything the upgrade needs to change — this is the artifact the next step works from, and it’s deliberately reviewable rather than silently applied.
Applying the Upgrade Report — Order Matters
This is the step that most separates upgrade.md from the more mechanical, one-shot nature of scaffolding. The instruction is explicit:
“Read the generated report and apply all steps in the order listed. The report contains file modifications, package version changes, and configuration updates. Apply them sequentially — order matters.”
Order matters because upgrade steps are often dependent — a config change in step 3 can assume a package version bump from step 1 already happened. Skipping around, or batching changes out of sequence, is how upgrades produce inconsistent, half-applied states that are harder to debug than either “fully upgraded” or “not upgraded at all.”
The report step also carries a specific warning worth sitting with: “If a step targets a customized file, merge carefully rather than overwriting custom logic.” This is the one place in the entire skill pack where the instruction isn’t “follow the flag/command exactly” — it’s an explicit acknowledgment that judgment is required. An agent (or a developer) blindly overwriting a file the report wants to touch, without checking whether that file has been customized, will silently destroy work that isn’t tracked anywhere except in that file’s prior git history — which is exactly why the clean-git-state precondition from step one matters: it’s the safety net for precisely this moment.
Verify: Build Clean Isn’t Optional
The upgrade isn’t done when the report’s steps are applied — it’s done when the project actually builds:
- Update dependencies:
npm install --silent --no-fund --no-audit— the same install discipline and flags from posts 2 and 3, including the minimum three-minute timeout rule from post 1 for SPFx’s larger-than-typical dependency tree. - Build and resolve every error:
npm run build. The skill is unambiguous here: “the upgrade is not complete until the build is clean.” A report fully applied but a build still failing is not a finished upgrade — it’s an upgrade in progress. - Fix deprecated or removed APIs flagged as build errors. Version upgrades routinely remove or rename APIs; these show up as compile errors, and fixing them is treated as part of the upgrade itself, not a separate follow-up task.
- Hand back to a human for the final check: serve the project (
heft starton v1.22+,gulp serveon legacy — the same toolchain split from post 2), smoke-test in the workbench, and review the git diff before committing. Even in an agent-driven workflow, this final review step is explicitly a human responsibility, not something the skill delegates away.
What’s Next
upgrade.md is the most procedurally strict of the four reference files — appropriately so, given it’s the one operating on code that already works. Clean git state going in, explicit version detection, order-dependent report application with room for human judgment on customized files, and a build-clean bar for “done.”
Right behind this post: post 5, a roadmap of constructive proposals for extending upgrade.md further — an explicit rollback path if a report can’t be fully applied, an incremental strategy for large version jumps, running the existing test suite as part of verification, and a machine-readable --output json alternative for agent-driven diffing. After that, the series continues with react-design.md in post 6.
Source note: Every command and rule in this post is quoted or closely paraphrased from SharePoint/spfx-dev-skills, specifically
plugins/spfx/skills/spfx/references/upgrade.md, current as of this writing.