Version 22 introduces Angular schematics for the builder packages, so you no longer have to wire builders into angular.json by hand:
ng add @angular-builders/jest— sets up the Jest builder as yourng testrunner. Detects an existing Karma, Vitest (Angular 22's new default), or Jest setup and migrates the test target accordingly.ng add @angular-builders/custom-esbuild/ng add @angular-builders/custom-webpack— scaffold the custom build setup.ng update @angular-builders/jest— runs the version migrations below automatically.
The ng update migration window is (from, to], so a project on any version from 17 through 21 can jump straight to 22 in a single ng update @angular-builders/jest. The v21 migration (dep bumps, Node16 tsconfig, option renames/removals — see the v20→v21 section below) and the v22 advisory both run in order.
ts-jest isolatedModules now defaults to true (previously implicitly false) for significantly faster compilation. This is a behavior change in the builder itself — it is not rewritten into your config.
Impact: a const enum shared across files, and type-only re-exports without the type modifier, will now error under isolatedModules.
- To keep the old behavior, set
isolatedModules: falsein your Jest config. - Otherwise, fix the call sites: convert
const enumto a regularenum(oras const), and useexport typefor type-only re-exports.
ng update @angular-builders/jest does not change this for you — it runs an advisory migration that warns and lists any const enum it finds. The new default is intentional.
coverageDirectory now defaults to <projectRoot>/coverage instead of ./coverage. In multi-project workspaces this prevents projects from overwriting each other's coverage reports.
Impact: update any CI/tooling that reads a hardcoded ./coverage/ path. The ng update advisory migration warns and lists affected projects.
@angular-builders/common — the loader shared by custom-esbuild, custom-webpack, and jest for your TypeScript config/plugin files (webpack.config.ts, esbuild plugins.ts, a .ts Jest config, etc.) — now uses jiti instead of ts-node. ts-node and tsconfig-paths are no longer dependencies of any @angular-builders package.
What changes for you:
- No build-time type-checking of config/plugin files.
jititranspiles (strips types) rather than type-checking. Your config runs the same, but a type error inside it no longer fails the build. To keep type-checking, runtsc --noEmiton those files separately (e.g. in CI). - The
NODE_OPTIONS='--loader ts-node/esm'workaround is gone. ESM apps previously neededTS_NODE_PROJECT/--loader ts-node/esmto load.tsconfigs;jitihandles ESM/CJS/TS natively, so those npm-script wrappers can be removed. ts-node/tsconfig-pathscan be dropped fromdevDependencies(unless you use them elsewhere).ts-node-specific tsconfig options (the"ts-node"section) no longer apply; path mappings belong incompilerOptions.
✅ Mostly automated. ng update @angular-builders/custom-esbuild / ng update @angular-builders/custom-webpack run a migration (the jest builder runs the same logic as an advisory) that:
- strips the
NODE_OPTIONS='--loader ts-node/esm'workaround from your npm scripts, - removes the
ts-node/tsconfig-pathsdevDependencies, - lifts path-mapping options out of the
"ts-node"tsconfig section intocompilerOptions.
tsc --noEmit step if you relied on it. Any non-path "ts-node" overrides that can't be migrated safely are logged as advisories rather than changed.
- No breaking changes beyond the shared
jitiloader change above and updating to Angular 22. ng add @angular-builders/custom-esbuildis now available.
- No breaking changes beyond the shared
jitiloader change above and updating to Angular 22. ng add @angular-builders/custom-webpackis now available (scaffolds awebpack.config.js).
Angular 22 unifies test runners under the @angular/build:unit-test builder with a runner option ("vitest" is the default for new apps; "karma" is still supported). @angular-builders/jest replaces this with its own :run target:
ng add @angular-builders/jestdetects a Karma, Vitest, or existing Jest setup and rewrites the test target to the Jest builder. For a Vitest project it also fixestsconfig.spec.jsontypes (vitest→jest) and advises on anyvi.*usages in your specs.- Karma is not removed in Angular 22 — it's deprecated. Running
ng update @angular/coreto v22 keeps existing Karma users on Karma (Angular rewrites the target to@angular/build:unit-testwithrunner: "karma"). Migrating to Jest stays opt-in viang add @angular-builders/jest.
Users of @angular-builders/jest must update their tsconfig.spec.json to include module and moduleResolution settings. See the Jest builder section below for details.
- Updated to support Angular 21's
@angular/buildschema changes - The
buildTargetandtsConfigproperties are no longer required in the unit-test builder (matching Angular 21's changes)
- No breaking changes (except for updating to Angular 21)
Breaking Change: jest-preset-angular has been updated from v14 to v16 to support Angular 21.
-
Update Jest to v30 -
jest-preset-angularv16 requires Jest 30:npm install --save-dev jest@^30.0.0 jest-environment-jsdom@^30.0.0 jsdom@^26.0.0
-
Update
tsconfig.spec.json- Angular 21 usesmoduleResolution: "bundler"by default, which is incompatible with Jest running in Node.js:{ "extends": "./tsconfig.json", "compilerOptions": { "module": "Node16", "moduleResolution": "Node16", "isolatedModules": true } }
The following builder options have been removed (Jest 30 no longer supports them):
browser- Removed from Jest 30init- Removed from Jest 30mapCoverage- Was deprecated, now removedtestURL- Removed (usetestEnvironmentOptions.urlin jest config instead)timers- Removed (usefakeTimersin jest config instead)
The following builder options have been renamed:
configPath→config(now also supports inline JSON configuration in addition to file paths)testPathPattern→testPathPatterns(now accepts multiple patterns)
The following defaults have changed:
testRunner- Default changed fromjasmine2tojest-circus/runnerglobalMocks- Default changed from["styleTransform", "matchMedia"]to["matchMedia"]. ThestyleTransform,getComputedStyle, anddoctypemocks have been removed as Jest 30's jsdom now supports these natively.zoneless- New option, defaults totruefor Angular 21+ zoneless applications. Set tofalseif your app uses zone.js change detection.
For more details, see the Jest 30 changelog and jest-preset-angular v16 changelog.
- Minimum Node.js version is now 20.19.0 (previously 18.19.1)
- Node.js 18 is no longer supported
All example projects have been migrated from the deprecated TSLint to modern ESLint using Angular's official migration tools. If you're using these examples as reference, update your linting setup accordingly by running ng add @angular-eslint/schematics.
-
The
forceEsbuildproperty has been removed from the dev-server configuration. This property is no longer supported since the builder now uses@angular/builddirectly, which uses esbuild by default.Before:
"serve": { "builder": "@angular-builders/custom-esbuild:dev-server", "options": { "forceEsbuild": true, "port": 5006 } }
After:
"serve": { "builder": "@angular-builders/custom-esbuild:dev-server", "options": { "port": 5006 } }
-
New Feature: Plugins can now access builder options and target information through factory functions. This is a non-breaking enhancement - existing plugins continue to work unchanged.
New capability:
// esbuild/plugins.ts import type { Plugin } from 'esbuild'; import type { ApplicationBuilderOptions } from '@angular-devkit/build-angular'; import type { Target } from '@angular-devkit/architect'; export default (builderOptions: ApplicationBuilderOptions, target: Target): Plugin => { return { name: 'project-aware-plugin', setup(build) { // Access current project name build.initialOptions.define.PROJECT_NAME = JSON.stringify(target.project); // Access builder options like outputPath, tsConfig, etc. console.log('Building for project:', target.project); console.log('Output path:', builderOptions.outputPath); }, }; };
This enables more sophisticated plugins that can adapt their behavior based on the current build target and configuration.
-
Migration to @angular/build: The custom-esbuild package now uses
@angular/buildinstead of@angular-devkit/build-angularfor better performance and modern build tooling.
- No breaking changes (except for updating to Angular 20)
- No breaking changes (except for updating to Angular 20)
- No breaking changes (except for updating to Angular 19)
- No breaking changes (except for updating to Angular 19)
- No breaking changes (except for updating to Angular 19)
- No breaking changes (except for updating to Angular 18)
- No breaking changes (except for updating to Angular 18)
- No breaking changes
- No breaking changes (except for updating to Angular 17)
- No breaking changes
- No breaking changes (except for updating to Angular 16)
- Jest 29 is required now, refer to its CHANGELOG for details.
jest-preset-angularhas been updated to version 13. Make sure you understand the implications and perform all the necessary changes to your code base as described injest-preset-angularCHANGELOG.- Global mocks for
getComputedStyleanddoctypeare disabled by default, thejsdomimplementation is used instead. The mocks are still available via the optionglobalMocks.
- No breaking changes (except for updating to Angular 15)
- No breaking changes (except for updating to Angular 15)
- Node 12 is no longer supported
- Node 12 is no longer supported
- Minimal required version of Jest is 28
- Command line arguments in camelCase are no longer supported, use kebab-case instead
- The default value of
getComputedStyleglobal mock is{}instead of{display: 'none', appearance: ['-webkit-appearance']} - If you use it with custom configuration, make sure you read this
- Node 12 is no longer supported
No breaking changes (except for updating to Angular 13)
jest-preset-angular has been updated to version 11.
- If you use it without custom configuration then no action required.
- If you use it with custom configuration, you might need to update it.
No breaking changes (except for updating to Angular 12)
- Jest 27 is required now
jest-preset-angularhas been updated to version 9, which uses Angular compiler instead ofts-jestin order to transform the TS files. Make sure you understand the implications and perform all the necessary changes to your code base as described injest-preset-angularCHANGELOG.
mergeStrategiesfield incustomWebpackConfighas been deprecated, usemergeRulesinstead as defined here.
In order to make this breaking change as backward compatible as possible, the default value of mergeRules is the following:
{
module: {
rules: {
test: "match",
use: {
loader: "match",
options: "merge",
},
},
},
};This is as close as possible to the smart merge strategy that was used before, so ideally if you didn't use mergeStrategies then your configuration should work just as it worked before.
Otherwise you'll have to adjust the mergeRules in accordance with your needs.
If you don't want to invest time in learning how the mergeRules work or you have a complicated use case then consider using Custom Webpack Config Function. This way you'll have full control over the configuration without relying on any merging mechanism.
- Update to Jest 26 if you still haven't.
@angular/architectandangular/coreare now direct builder dependencies, therefore no need to specify them explicitly inpackage.json
-
jest-preset-angular version has been updated to 8. If you have any custom Jest configuration, make sure it matches the preset version.
-
If you're using Ivy (enabled by default in version 9) make sure you run
ngccin apostinstallhook. For more details refer to this issue.
index.htmlis no longer generated with Webpack. This means if your solution uses Webpack to alterindex.htmlit will stop working the moment you upgrade to version 8.
Instead you should useindexTransformproperty.
@angular-builders/dev-server:generichas been deprecated. Use@angular-builders/custom-webpack:dev-serverinstead.
- Update to Jest 24 if you still haven't.