Home / Articles

Migrating an Angular App from the Webpack Builder to @angular/build

A step-by-step guide to replacing Angular's Webpack browser builder with the esbuild-based application builder, fixing output paths, SSR, loaders and tsconfig types.

Publisher: REACTAPP.TOP4 min read942 words

This article is published in English.

Sources: Webpack is Officially Deprecated in Angular 22: The TSGo Migration

For years, Angular projects were built through Webpack via @angular-devkit/build-angular. The CLI's default is now the esbuild-based application builder from @angular/build, and the Webpack builders are on the way out: according to the Angular 22 release notes as reported at the time of writing, the Webpack-based builder is formally deprecated. The steps below show how to move an existing application to the new builder, what changes in angular.json, what to do about custom Webpack loaders, and how to prepare the TypeScript configuration for the native Go compiler.

Why the move matters now

Beyond deprecation, there is a performance motive. TypeScript 7.0, a port of the compiler to Go known as TSGo or Project Corsa, was at release-candidate stage when this was written and is advertised as up to 10 times faster than the JavaScript-based compiler. Angular's roadmap points toward building on that compiler, and the tooling investment is going into the esbuild and Vite pipeline rather than Webpack. Webpack projects will miss those gains. Treat the timelines as time-sensitive and check current announcements.

The new builder also simplifies the target layout. The Webpack setup needed separate builders for the browser bundle, the server bundle and prerendering; the application builder produces all of them from a single target.

Step 1: swap the builder in angular.json

Open angular.json, find the build target of your project, and locate the legacy browser builder:

// DELETE the legacy Webpack builder
"build": {
  "builder": "@angular-devkit/build-angular:browser",
  "options": { ... }
}

Replace the builder name with the unified application builder, keeping the options object for now:

// MIGRATE to the unified esbuild application builder
"build": {
  "builder": "@angular/build:application",
  "options": { ... }
}

Recent CLI versions also offer an automated migration through ng update that performs this and the following option changes; check the Angular documentation for the exact command for your version, then review the diff it produces.

Step 2: adjust the build options

The application builder validates its options more strictly, so several entries in build.options need attention.

  • Rename main to browser. The client entry point is now configured with the browser option; main is no longer accepted.
  • Decide on the output layout. With a plain string such as "outputPath": "dist/app", the builder creates browser and server subdirectories inside it. Deployment scripts that expect files directly in dist/app will break. To keep a flat client output, use the object form and set browser to an empty string:
"outputPath": {   "base": "dist/app",   "browser": "" }
  • Fold SSR into the same target. If the app uses server-side rendering, remove the separate server architect target and move the server entry point into the application builder's options, enabling prerendering there as needed:
"server": "src/main.server.ts", "prerender": true

Then run a production build and compare the output with what your server or CDN expects.

Step 3: replace custom Webpack loaders

Projects that extend the build with @angular-builders/custom-webpack are hit hardest: any custom loader, such as raw SVG imports or a Markdown transformer, stops working the moment Webpack leaves the chain. There are two routes forward:

  • Assets such as SVGs: rely on Angular's built-in assets configuration or reference them from CSS instead of importing them through a loader.
  • Custom transformations: reimplement them as an esbuild plugin and register it through @angular-builders/custom-esbuild.

Inventory these customizations first; they usually take the most engineering time.

Step 4: prepare tsconfig for TypeScript 7

Angular 22 continues to support TypeScript 5.x and 6.x, so TSGo is not required yet. It does, however, change defaults that can break type-checking. The most visible one is types: it defaults to an empty array, so ambient global declarations from packages such as @types/node or @types/jest are no longer picked up automatically. Globals like process, describe or expect then produce "cannot find name" errors.

The fix is to list the ambient type packages each project needs explicitly:

// tsconfig.json
"compilerOptions": {
  // You must now explicitly declare ambient types for TSGo compatibility
  "types": ["node", "jest"]
}

Set this per tsconfig: application code typically needs fewer globals than test code, and listing jest in the app config would leak test globals into production types.

Migration checklist

  • Replace @angular-devkit/build-angular:browser with @angular/build:application in angular.json.
  • Rename main to browser, choose an outputPath layout, and merge SSR settings into the single target.
  • Port custom Webpack loaders to asset configuration or esbuild plugins.
  • Remove @ngtools/webpack and other Webpack-only build dependencies from package.json once nothing references them.
  • Declare ambient types explicitly in each tsconfig ahead of TypeScript 7.

The builder swap itself is a small configuration change; the effort lies in custom loaders and deployment paths. Doing it now removes the dependency on a deprecated pipeline and positions the project to benefit from faster compilers as they land. For setting up a fresh project on the current toolchain, see setting up a modern Angular 22 project.