Skip to content
SunnyWriteUps
Go back

The Control Room of Your Angular Workspace

Edit page

At first glance, it looks like a massive, deeply nested wall of text. It’s easy to ignore it and let the Angular CLI do its magic behind the scenes. However, understanding angular.json is a rite of passage for Angular developers. It is the heart of your workspace, dictating how your app is built, served, tested, and deployed.

Let’s break down the angular.json file, translating its key-value pairs from machine-speak into plain English.


The Root Level: The Lay of the Land

When you collapse all the nested objects, the root of angular.json is surprisingly simple. It defines the workspace environment.

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": { ... }
}

The projects Object: Your Apps and Libraries

Inside projects, you will find a key for your main application (usually named whatever you called your app when running ng new). If your app is named my-awesome-app, you’ll see:

"projects": {
  "my-awesome-app": {
    "projectType": "application",
    "root": "",
    "sourceRoot": "src",
    "prefix": "app",
    "architect": { ... }
  }
}

Deep Dive into architect: Building, Serving, and Testing

The architect node contains commands (also called “targets”) like build, serve, test, and extract-i18n. When you run a command like ng serve in your terminal, the Angular CLI looks inside the architect.serve block to figure out exactly what to do.

Let’s look at the most important target: build.

"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {
      "outputPath": "dist/my-awesome-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": []
    },
    "configurations": { ... }
  }
}

1. builder

This is the tool under the hood that executes the task. For standard web apps, it’s usually @angular-devkit/build-angular:browser (using Webpack) or :application (if you’re using the newer esbuild system).

2. options

These are the default settings used when you run ng build.

3. configurations

This is arguably the most powerful feature in the file. It allows you to override the default options based on specific environments (like production or development).

"configurations": {
  "production": {
    "fileReplacements": [
      {
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.prod.ts"
      }
    ],
    "optimization": true,
    "sourceMap": false
  },
  "development": {
    "optimization": false,
    "sourceMap": true
  }
}

When you run ng build --configuration production, Angular merges the options block with the configurations.production block.


The serve Target

Finally, let’s briefly look at the serve target. This is what runs when you type ng serve.

"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",
  "options": {
    "browserTarget": "my-awesome-app:build"
  },
  "configurations": {
    "production": {
      "browserTarget": "my-awesome-app:build:production"
    }
  }
}

Notice the browserTarget key. The serve command doesn’t actually compile your code itself; it just tells the build target to run in memory and host the result on localhost:4200.

Summary

While angular.json can feel overwhelming, it’s highly logical once you understand the hierarchy:

  1. Workspace (projects) ->
  2. Specific App (my-awesome-app) ->
  3. Command (architect -> build) ->
  4. How to do it (builder, options, configurations).

Mastering this file allows you to effortlessly add global stylesheets, manage multiple environments, and control exactly how your Angular app gets bundled for the real world.


Edit page
Share this post on:

Previous Post
Angular component dependency graph