Skip to main content

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
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

@angular/build:extract-i18n

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:
outputPath
string | object
Where to write build output files
outputHashing
string
Hash output files for cache busting: none, all, media, bundles
index
string
Path to index.html file
browser
string
Main browser entry point (for application builder)
main
string
Main entry point (for browser builder)
polyfills
string[]
Polyfills to include
tsConfig
string
Path to TypeScript configuration file
aot
boolean
default:"true"
Enable Ahead-of-Time compilation
assets
array
Static assets to copy
"assets": [
  "src/favicon.ico",
  "src/assets",
  {
    "glob": "**/*",
    "input": "src/assets/",
    "output": "/assets/"
  }
]
styles
array
Global stylesheets to include
scripts
array
Global scripts to include
optimization
boolean | object
Enable optimization (minification, tree-shaking)
"optimization": {
  "scripts": true,
  "styles": true,
  "fonts": true
}
sourceMap
boolean
Generate source maps
namedChunks
boolean
Use human-readable chunk names
extractLicenses
boolean
Extract third-party licenses to separate file
budgets
array
Size budgets for application
"budgets": [
  {
    "type": "initial",
    "maximumWarning": "2mb",
    "maximumError": "5mb"
  },
  {
    "type": "anyComponentStyle",
    "maximumWarning": "6kb",
    "maximumError": "10kb"
  }
]

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

1

Create Builder Package

ng generate library my-builder
2

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"]
}
3

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);
4

Register Builder

Add to builders.json:
{
  "builders": {
    "my-builder": {
      "implementation": "./src/builder.ts",
      "schema": "./src/schema.json",
      "description": "My custom builder"
    }
  }
}
5

Use in angular.json

{
  "architect": {
    "custom": {
      "builder": "my-library:my-builder",
      "options": {
        "option1": "value"
      }
    }
  }
}

Running Custom Builder

ng run my-app:custom

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"
}

Performance Budgets

Set size limits to maintain performance:
{
  "type": "initial",
  "maximumWarning": "2mb",
  "maximumError": "5mb"
}
Total size of initial bundle.

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