What are Builders?
Builders are the underlying execution engine for Angular CLI commands. They are part of the Angular Architect API and define how commands like ng build, ng test, and ng serve actually work. Each builder is a function that performs a specific task according to a target configuration defined in angular.json.
Builders are similar to webpack plugins or Gulp tasks - they’re modular units that perform specific build operations.
Builder Architecture
The Angular CLI uses the Architect system to run builders:
Key Concepts
Target A named builder configuration in angular.json (e.g., “build”, “test”)
Builder The actual implementation that performs the work
Options Configuration parameters passed to the builder
Configurations Named option overrides (e.g., “production”, “development”)
Official Builders
Angular provides several official builders:
Application Builders
The modern application builder (Angular v17+) using esbuild and Vite. {
"architect" : {
"build" : {
"builder" : "@angular/build:application" ,
"options" : {
"outputPath" : {
"base" : "dist" ,
"browser" : ""
},
"index" : "src/index.html" ,
"browser" : "src/main.ts" ,
"polyfills" : [ "zone.js" ],
"tsConfig" : "tsconfig.app.json" ,
"assets" : [ "src/favicon.ico" , "src/assets" ],
"styles" : [ "src/styles.css" ],
"scripts" : []
}
}
}
}
Features:
Fast builds with esbuild
Improved development server
Better optimization
SSR/SSG support out of the box
Traditional browser application builder using webpack. {
"architect" : {
"build" : {
"builder" : "@angular-devkit/build-angular:browser" ,
"options" : {
"outputPath" : "dist/my-app" ,
"index" : "src/index.html" ,
"main" : "src/main.ts" ,
"polyfills" : "src/polyfills.ts" ,
"tsConfig" : "tsconfig.app.json" ,
"assets" : [ "src/favicon.ico" , "src/assets" ],
"styles" : [ "src/styles.css" ],
"scripts" : []
}
}
}
}
Use cases:
Legacy projects
Custom webpack configurations
Specific webpack plugins required
Angular v17+ recommends using @angular/build:application for new projects.
Development Server Builders
@angular/build:dev-server
Development server for the application builder:
{
"architect" : {
"serve" : {
"builder" : "@angular/build:dev-server" ,
"options" : {
"buildTarget" : "my-app:build"
},
"configurations" : {
"production" : {
"buildTarget" : "my-app:build:production"
},
"development" : {
"buildTarget" : "my-app:build:development"
}
}
}
}
}
Key Options:
buildTarget: Which build configuration to serve
port: Development server port
host: Host address
ssl: Enable HTTPS
proxyConfig: API proxy configuration
Test Builder
@angular-devkit/build-angular:karma
Runs unit tests with Karma:
{
"architect" : {
"test" : {
"builder" : "@angular-devkit/build-angular:karma" ,
"options" : {
"polyfills" : [ "zone.js" , "zone.js/testing" ],
"tsConfig" : "tsconfig.spec.json" ,
"karmaConfig" : "karma.conf.js" ,
"assets" : [ "src/favicon.ico" , "src/assets" ],
"styles" : [ "src/styles.css" ],
"scripts" : []
}
}
}
}
Options:
karmaConfig: Path to Karma configuration
watch: Watch files for changes
codeCoverage: Generate coverage reports
browsers: Browsers to run tests in
The Angular team uses Karma 6.4.0 for testing in the source repository.
Internationalization Builder
Extracts i18n messages from templates:
{
"architect" : {
"extract-i18n" : {
"builder" : "@angular/build:extract-i18n" ,
"options" : {
"buildTarget" : "my-app:build"
}
}
}
}
Lint Builder
@angular/build:tslint
Runs TSLint on the project:
{
"architect" : {
"lint" : {
"builder" : "@angular/build:tslint" ,
"options" : {
"tsConfig" : [
"tsconfig.app.json" ,
"tsconfig.spec.json"
],
"exclude" : [ "**/node_modules/**" ]
}
}
}
}
TSLint is deprecated. Consider migrating to ESLint with @angular-eslint.
Builder Options
Common Options
These options are available across multiple builders:
Where to write build output files
Hash output files for cache busting: none, all, media, bundles
Main browser entry point (for application builder)
Main entry point (for browser builder)
Path to TypeScript configuration file
Enable Ahead-of-Time compilation
Static assets to copy "assets" : [
"src/favicon.ico" ,
"src/assets" ,
{
"glob" : "**/*" ,
"input" : "src/assets/" ,
"output" : "/assets/"
}
]
Global stylesheets to include
Global scripts to include
Enable optimization (minification, tree-shaking) "optimization" : {
"scripts" : true ,
"styles" : true ,
"fonts" : true
}
Use human-readable chunk names
Extract third-party licenses to separate file
Build Configurations
Configurations are named sets of option overrides:
{
"architect" : {
"build" : {
"builder" : "@angular/build:application" ,
"options" : {
"outputHashing" : "none" ,
"optimization" : false ,
"sourceMap" : true
},
"configurations" : {
"production" : {
"optimization" : true ,
"outputHashing" : "all" ,
"sourceMap" : false ,
"namedChunks" : false ,
"extractLicenses" : true ,
"budgets" : [
{
"type" : "initial" ,
"maximumWarning" : "2mb" ,
"maximumError" : "5mb"
}
]
},
"development" : {
"optimization" : false ,
"sourceMap" : true ,
"namedChunks" : true
}
},
"defaultConfiguration" : "production"
}
}
}
Using Configurations
# Use production configuration
ng build --configuration=production
ng build -c production
# Use development configuration
ng build --configuration=development
Custom Builders
You can create custom builders for specialized build tasks.
Creating a Custom Builder
Create Builder Package
ng generate library my-builder
Define Builder Schema
Create schema.json: {
"$schema" : "http://json-schema.org/draft-07/schema" ,
"type" : "object" ,
"properties" : {
"option1" : {
"type" : "string" ,
"description" : "An example option"
}
},
"required" : [ "option1" ]
}
Implement Builder
import { BuilderContext , BuilderOutput , createBuilder } from '@angular-devkit/architect' ;
import { JsonObject } from '@angular-devkit/core' ;
interface Options extends JsonObject {
option1 : string ;
}
async function myBuilder (
options : Options ,
context : BuilderContext
) : Promise < BuilderOutput > {
context . reportStatus ( `Running with option: ${ options . option1 } ` );
// Perform build tasks
try {
// Your build logic here
return { success: true };
} catch ( error ) {
context . reportStatus ( 'Error: ' + error . message );
return { success: false };
}
}
export default createBuilder ( myBuilder ) ;
Register Builder
Add to builders.json: {
"builders" : {
"my-builder" : {
"implementation" : "./src/builder.ts" ,
"schema" : "./src/schema.json" ,
"description" : "My custom builder"
}
}
}
Use in angular.json
{
"architect" : {
"custom" : {
"builder" : "my-library:my-builder" ,
"options" : {
"option1" : "value"
}
}
}
}
Running Custom Builder
Builder Context
Builders receive a BuilderContext with useful utilities:
interface BuilderContext {
// Logging
logger : Logger ;
reportStatus ( status : string ) : void ;
reportProgress ( current : number , total ?: number , status ?: string ) : void ;
// Workspace information
workspaceRoot : string ;
currentDirectory : string ;
// Target information
target ?: Target ;
// Schedule other builders
scheduleBuilder ( builder : string , options : JsonObject ) : Promise < BuilderRun >;
scheduleTarget ( target : Target , overrides ?: JsonObject ) : Promise < BuilderRun >;
// Get target options
getTargetOptions ( target : Target ) : Promise < JsonObject >;
// Validate options
validateOptions < T extends JsonObject >( options : JsonObject , builderName : string ) : Promise < T >;
}
File Replacements
Replace files during build based on configuration:
{
"configurations" : {
"production" : {
"fileReplacements" : [
{
"replace" : "src/environments/environment.ts" ,
"with" : "src/environments/environment.prod.ts"
}
]
}
}
}
Useful for environment-specific configurations.
Build Optimization Strategies
Code Splitting
{
"optimization" : true ,
"namedChunks" : false ,
"commonChunk" : true
}
Tree Shaking
Enabled automatically with optimization:
{
"optimization" : {
"scripts" : true
}
}
Differential Loading
Generate separate bundles for modern and legacy browsers:
{
"tsConfig" : "tsconfig.app.json" ,
"browserslist" : ".browserslistrc"
}
Set size limits to maintain performance:
Initial Budget
Component Styles
All Scripts
Lazy Bundles
{
"type" : "initial" ,
"maximumWarning" : "2mb" ,
"maximumError" : "5mb"
}
Total size of initial bundle. {
"type" : "anyComponentStyle" ,
"maximumWarning" : "6kb" ,
"maximumError" : "10kb"
}
Size of individual component styles. {
"type" : "allScript" ,
"maximumWarning" : "500kb" ,
"maximumError" : "1mb"
}
Total size of all scripts. {
"type" : "anyComponentStyle" ,
"maximumWarning" : "100kb" ,
"maximumError" : "200kb"
}
Size of lazy-loaded bundles.
Proxy Configuration
Configure API proxying for development:
proxy.conf.json:
{
"/api" : {
"target" : "http://localhost:3000" ,
"secure" : false ,
"changeOrigin" : true ,
"pathRewrite" : {
"^/api" : ""
}
}
}
angular.json:
{
"serve" : {
"options" : {
"proxyConfig" : "proxy.conf.json"
}
}
}
Build Events
Builders emit events during execution:
import { BuilderOutput } from '@angular-devkit/architect' ;
import { Observable } from 'rxjs' ;
function myBuilder ( options : Options ) : Observable < BuilderOutput > {
return new Observable ( subscriber => {
// Emit progress
subscriber . next ({ success: false , progress: 0.5 });
// Complete build
subscriber . next ({ success: true });
subscriber . complete ();
});
}
Next Steps
Schematics Create custom code generators
CLI Commands Master all Angular CLI commands
Resources
Architect API Official builder documentation
Builder Examples Angular DevKit builders source