If you’ve been building SharePoint Framework solutions for a while, you already know Gulp. It’s been the backbone of every SPFx project since day one — running your builds, serving the workbench, packaging your .sppkg files. But that era is officially over.
With SPFx v1.22, Microsoft replaced the Gulp-based toolchain with Heft — a config-driven build orchestrator from the Rush Stack ecosystem. Starting with SPFx v1.23, all new projects will use Heft by default. And by v1.24, the Gulp-based pipeline will be officially unsupported.
So if you have existing projects still running on Gulp, now is the time to migrate. In this tutorial, I will explain how to migrate from a Gulp-based to a Heft-based toolchain in the SharePoint Framework (SPFx) step by step.
What is Heft in SharePoint Framework?
In SPFx (SharePoint Framework), Heft is basically a build and task management tool that helps run and organize all the behind-the-scenes processes when you develop a SharePoint solution.
Think of Heft as a modern replacement for older tools like Gulp in SPFx. Starting from SPFx v1.22, Microsoft officially switched from Gulp to Heft to make builds cleaner and faster.
When you’re building an SPFx project, a lot of things need to happen automatically:
- Compile TypeScript → JavaScript
- Bundle your code
- Run linting (check code quality)
- Execute tests
- Build the final package ready for SharePoint
Heft handles all of this automatically — you just run one command like heft build or heft start, and it takes care of the rest behind the scenes.
Instead of writing custom task scripts like you used to with Gulp, Heft uses simple JSON configuration files to define what to do, making your project easier to maintain and understand.
A new SPFx project already comes pre-configured with Heft through something called a rig (a shared settings package). So you don’t need to set anything up yourself — it just works out of the box.
Here’s a quick comparison between Gulp and Heft.
| Area | Gulp (Legacy) | Heft (SPFx v1.22+) |
|---|---|---|
| Core model | Custom JS tasks in gulpfile.js | Config-driven with plugins and rigs |
| Extensibility | Write custom tasks per project | Use Heft plugins or patch files |
| Performance | Sequential tasks, no caching | Incremental builds and caching |
| Config location | Scattered across gulpfile.js | Centralized JSON files (heft.json, etc.) |
| Scale | Hard to keep consistent across repos | Built to scale with Rush Stack monorepos |
Heft makes SPFx development cleaner and more modern by replacing the old Gulp-based system with a structured, configuration-driven approach.
Check out Set Up Your SharePoint Framework (SPFx) Development Environment using Heft Toolchain
Before You Start — A Few Things to Check
Don’t jump straight to uninstalling packages. Do these first:
- Back up your project. Either copy the folder or make sure all your code is committed to source control. The migration makes sweeping changes to your config files and
package.json. - Check your Node.js version. SPFx v1.22 requires Node v22. Run
node -vto confirm. If you’re on an older version, update first. - Check for gulp customizations. Open your
gulpfile.jsand look for any custom tasks — things likebuild.configureWebpack.mergeConfig(),build.rig.addPreBuildTask(), or custom copy/lint steps. You’ll need to translate these to Heft plugins after the migration. Note these down before you delete anything.
Migrate from Gulp based to Heft based Toolchain in SPFx
Follow the steps below to migrate from Gulp based to Heft based Toolchain in SharePoint Framework (SPFx).
Step 1: Uninstall the Gulp Toolchain
The first thing to do is rip out the old Gulp-based packages. Run this command from your project root:
npm uninstall @microsoft/sp-build-web ajv gulp

Next, uninstall the TypeScript compiler wrapper. The default SPFx v1.21.1 project uses TypeScript 5.3, so:
npm uninstall @microsoft/rush-stack-compiler-5.3
If your project uses a different TypeScript version, replace 5.3 with whatever version you have. Check your package.json devDependencies — look for @microsoft/rush-stack-compiler-*.

Step 2: Install the Heft Toolchain
Now install all the Heft-related packages your project needs:
npm install @microsoft/spfx-web-build-rig@1.22.1 @microsoft/spfx-heft-plugins@1.22.1 @microsoft/eslint-config-spfx@1.22.1 @microsoft/eslint-plugin-spfx@1.22.1 @microsoft/sp-module-interfaces@1.22.1 @rushstack/eslint-config@4.5.2 @rushstack/heft@1.1.2 @types/heft-jest@1.0.2 @typescript-eslint/parser@8.46.2 --save-dev --save-exact --force
That --force flag is there because some peer dependency conflicts can pop up during migration. It’s fine to use here — you’re intentionally replacing the old toolchain.
If you also want to upgrade TypeScript to v5.8 (optional but recommended), run:
npm install typescript@~5.8.0 --save-dev

Heads up: If you run into issues installing TypeScript v5.8 during migration, you can skip this for now. The toolchain works fine with TypeScript v5.3 too.
Step 3: Update Your NPM Scripts
Open your package.json and replace the old Gulp-based scripts with Heft equivalents. Find the scripts section and update it like this:
{
"scripts": {
"build": "heft build --clean",
"clean": "heft clean",
"test": "heft test",
"test-only": "heft run --only test --",
"deploy": "heft dev-deploy",
"start": "heft start --clean",
"build-watch": "heft build --lite",
"package-solution": "heft package-solution",
"deploy-azure-storage": "heft deploy-azure-storage",
"eject-webpack": "heft eject-webpack",
"trust-dev-cert": "heft trust-dev-cert",
"untrust-dev-cert": "heft untrust-dev-cert"
}
}

Here’s how the old Gulp commands map to Heft:
| Gulp command | Heft equivalent |
|---|---|
gulp serve | heft start |
gulp build | heft build |
gulp bundle --ship | heft build --production |
gulp package-solution --ship | heft package-solution --production |
gulp clean | heft clean |
Read How to Change Solution Name in SPFx
Step 4: Add the SPFx Heft Rig
Heft uses a concept called rigs — shared build configurations that multiple projects can extend. This is what replaces the old sp-build-web rig from the Gulp days.
Create a new file at ./config/rig.json with this content:
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@microsoft/spfx-web-build-rig"
}

This one file tells Heft: “use the SPFx web build rig for all the default build settings.” You don’t have to define TypeScript paths, Webpack entry points, or ESLint configs from scratch — the rig handles all of that for you.
Step 5: Replace the Sass Configuration
Open ./config/sass.json and replace everything in it with:
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json",
"extends": "@microsoft/spfx-web-build-rig/profiles/default/config/sass.json"
}

This hooks your project’s Sass compilation into the Heft Sass plugin defined by the rig. If you had custom Sass settings in the old file (like useCSSModules or postProcessedFileExtensions), you can add those back here — they’ll override the rig’s defaults.
Step 6: Add the TypeScript Plugin Configuration
Create a new file at ./config/typescript.json:
{
"extends": "@microsoft/spfx-web-build-rig/profiles/default/config/typescript.json",
"staticAssetsToCopy": {
"fileExtensions": [".resx", ".jpg", ".png", ".woff", ".eot", ".ttf", ".svg", ".gif"],
"includeGlobs": ["webparts/*/loc/*.js"]
}
}

The staticAssetsToCopy section tells Heft which non-TypeScript files to copy over during the build. This replaces what gulp copy-assets or similar custom tasks used to handle. Adjust the file extensions and globs to match whatever your project actually needs.
Check out How to Install NVM in Windows
Step 7: Update tsconfig.json
Replace the contents of your existing ./tsconfig.json with this:
{
"extends": "./node_modules/@microsoft/spfx-web-build-rig/profiles/default/tsconfig-base.json"
}
Your old tsconfig.json probably had a long list of compiler options. All of those are now inherited from the rig’s base config. You only need to add project-specific overrides here if you have them.
Step 8: Delete gulpfile.js
Just delete it.
rm gulpfile.js
If you had custom tasks in your gulpfile.js — like custom Webpack config, pre-build steps, or post-build file operations — don’t delete it yet. Keep it open in a separate window for reference while you set up the equivalent Heft plugins in the next section.
Step 9: Upgrade Your SPFx Production Dependencies
Update the core SPFx packages to v1.22:
npm install @microsoft/sp-component-base@1.22.1 @microsoft/sp-core-library@1.22.1 @microsoft/sp-lodash-subset@1.22.1 @microsoft/sp-office-ui-fabric-core@1.22.1 @microsoft/sp-property-pane@1.22.1 @microsoft/sp-webpart-base@1.22.1 --save-exact

After making so many changes to packages, I’d strongly recommend doing a full clean reinstall:
# Windows (PowerShell)
Remove-Item -Recurse -Force node_modules
Remove-Item -Force package-lock.json
# Mac/Linux
rm -rf node_modules package-lock.json
# Then reinstall everything cleanly
npm install
This ensures your dependency tree is consistent and you’re not carrying over any stale Gulp-related packages.
Step 10: Test the Migration
Run a build to verify everything works:
npm run build
Or if you have Heft installed globally:
heft build --production
If the build completes without errors, you’re done with the core migration. Fire up the dev server with:
npm run start
# or
heft start --clean

This will automatically open the workbench url. In case you are getting an error like in the image below.

Just run the following command.
npm run trust-dev-cert

Then, re-run the npm run start command; this time, without errors, you can get your web part as shown below.

Handling Custom gulpfile.js Tasks
This is where it gets more involved. If your old gulpfile.js was just the default SPFx boilerplate, you’re done. But if you had custom tasks, here’s how to handle the most common ones:
Custom Webpack Configuration
If you were using build.configureWebpack.mergeConfig() to inject custom Webpack settings, you have two options in Heft:
Option 1 — Use the webpack patch file (simpler):
Create a file at ./config/webpack.extend.js:
module.exports = function (existingConfig) {
existingConfig.resolve = existingConfig.resolve || {};
existingConfig.resolve.alias = {
...existingConfig.resolve.alias,
'@myAlias': require('path').resolve(__dirname, '../src/helpers')
};
return existingConfig;
};
Then reference it in your heft.json (more on that file below).
Option 2 — Eject Webpack entirely (for complex cases):
heft eject-webpack
This generates a full webpack.config.js in your project that you can modify directly. It’s the escape hatch for when you need complete control.
Custom Pre/Post Build Tasks
If you had build.rig.addPreBuildTask() or addPostBuildTask() For things like copying extra files or running scripts, use Heft’s run-script-plugin.
Create ./config/heft.json:
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",
"extends": "@microsoft/spfx-web-build-rig/profiles/default/config/heft.json",
"phasesByName": {
"build": {
"tasksByName": {
"my-custom-script": {
"taskPlugin": {
"pluginPackage": "@rushstack/heft",
"pluginName": "run-script-plugin",
"options": {
"scriptPath": "./scripts/my-custom-task.js"
}
}
}
}
}
}
}
Create ./scripts/my-custom-task.js and put your custom logic there. This script runs as part of the build phase.
Copying Files
The old build.copyStaticAssets type of operations now live in typescript.json under staticAssetsToCopy (which we already configured in Step 6). For more complex copy scenarios, use the copy-files-plugin in heft.json.
Common Issues and Fixes
A few things that tend to trip people up during migration:
- ESLint errors after migration: Your old
.eslintrc.jsmay reference@microsoft/eslint-config-spfxin a way that conflicts with the new package. Update theextendsin your ESLint config to use@rushstack/eslint-configand re-run the build. - “Cannot find module” errors: Usually means stale
node_modules. Do the clean reinstall from Step 9. - TypeScript errors you didn’t have before: If you upgraded to TypeScript v5.8, some stricter type checks may now flag issues that were silently ignored before. Fix them or stay on TypeScript v5.3 for now.
- PnP SPFx Controls not working: If you use
@pnp/spfx-controls-react, make sure you’re on a version that supports SPFx v1.22. Runnpm ls @pnp/spfx-controls-reactto check your current version and compare with their release notes. - Dev cert issues: If HTTPS fails on the local workbench, run
heft trust-dev-certto re-trust the certificate.
Using the M365 CLI to Generate an Upgrade Report (Optional but Helpful)
If you want a full list of every change needed for your specific project before you manually edit anything, the Microsoft 365 CLI can generate an upgrade report for you:
# Install M365 CLI if you don't have it
npm i -g @pnp/cli-microsoft365
# Generate the upgrade report
m365 spfx project upgrade --toVersion 1.22.0 --preview --output md > upgrade-report.md
Open upgrade-report.md — it will list every dependency that needs to change, every script to update, and any manual steps specific to your project. It’s a great way to audit before you start making changes.
What the Final Project Structure Looks Like
After migration, here’s what your key config files should look like:
your-spfx-project/
├── config/
│ ├── rig.json ← NEW (points to spfx-web-build-rig)
│ ├── heft.json ← NEW (only if you have custom tasks)
│ ├── sass.json ← UPDATED (now extends rig)
│ ├── typescript.json ← NEW (configures TS plugin)
│ └── package-solution.json (unchanged)
├── tsconfig.json ← UPDATED (now extends rig's base config)
├── package.json ← UPDATED (scripts use heft commands)
├── gulpfile.js ← DELETED
└── src/ (unchanged)

Wrapping Up
In this tutorial, I explained how to migrate from Gulp based toolchain to Heft based toolchain in the SharePoint Framework (SPFx). Follow the above steps, and you should be able to migrate your project.
The key things to remember:
- Uninstall the old Gulp packages and install the Heft equivalents
- Add
rig.jsonto point to@microsoft/spfx-web-build-rig - Update your config files (sass.json, typescript.json, tsconfig.json)
- Replace your npm scripts with
heftcommands - Delete
gulpfile.js(but migrate any custom tasks first) - Do a clean
npm installat the end to flush out any stale dependencies
If you’ve got custom Gulp tasks, the translation to Heft plugins takes a bit of extra thought — but the run-script-plugin and copy-files-plugin cover most real-world scenarios.
Also, you may like:
- Create a Modal Popup in SPFx
- Bind SharePoint List Items to SPFx Fluent UI React Dropdown
- Customize SharePoint List Command Bar Download Button Using SPFx Extension
- Upload File to SharePoint Document Library With Metadata in SPFx

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.