Skip to content

Avoiding Browser Subfolder in Angular 18 Builds with Custom Output Path

Problem Statement

When upgrading to Angular 18, the new application builder changes how build outputs are structured. By default, it places browser assets in a /browser subfolder (dist/project-x/browser). While you can configure angular.json to eliminate this subfolder in standard builds, a problem arises when overriding the output path via the command line:

bash
ng build --output-path=/custom/path --watch

This unexpectedly creates the browser files in /custom/path/browser instead of /custom/path. This is problematic when:

  1. Your deployment pipeline expects flat directory structures
  2. You need real-time builds (--watch) to output directly to a specific location
  3. You want to avoid hardcoding paths in your angular.json

Solution: Custom Configuration for Watched Builds

The optimal solution is to create a dedicated build configuration that combines your desired settings. This preserves your default configurations while providing a path-free approach.

Step-by-Step Implementation

  1. Create a new configuration in angular.json under your project's build configurations:
json
// angular.json
{
  "projects": {
    "project-x": {
      "architect": {
        "build": {
          "configurations": {
            "development": { ... }, // Your existing config

            // Add new configuration for watcher
            "dev-watch": {
              "inherits": "development", // Inherit properties from 'development'
              "outputPath": {
                "base": "/projects/project-x-backend/wwwroot",
                "browser": "" // Outputs browser files directly to 'base'
              },
              "watch": true // Optional: Enable watch mode by default
            }
          }
        }
      }
    }
  }
}
  1. Execute the build using the new configuration:
bash
ng build --base-href=/x/ --configuration dev-watch --verbose

Key Improvements

  • 🧩 inherits property: Angular 18's new feature let configurations share settings (no manual duplication)
  • 🕒 Auto-enable watch: Add "watch": true to make --watch implicit in this configuration
  • 🧠 Path agnostic: Works with any output directory without command-line overrides

Why This Works

  • Setting "browser": "" forces files to output directly to the base path
  • The dedicated dev-watch configuration keeps your development settings pristine
  • Angular CLI properly merges inherited properties with local overrides

Alternative Solutions

1. Global Configuration Change (In angular.json)

json
{
  "projects": {
    "project-x": {
      "architect": {
        "build": {
          "options": {
            "outputPath": {
              "base": "dist/project-x",
              "browser": ""
            }
          }
        }
      }
    }
  }
}
  • Pros: Simpler setup
  • Cons: Applies to all builds, may conflict if you need different paths for other workflows

2. Using the Deprecated Browser Builder

Not Recommended

json
"builder": "@angular-devkit/build-angular:browser",
"options": {
  "outputPath": "dist",
  "main": "src/main.ts" // Note 'main' instead of 'browser'
}
  • ⚠️ Uses outdated Webpack builder (Angular 18 defaults to esbuild)
  • 🚫 Loses advantages of the new application builder
  • ❌ Official deprecation path announced

Best Practices

  1. Prefer configurations over CLI flags for environment-specific settings
  2. Leverage inherits to reduce configuration duplication
  3. Test with --verbose when modifying output paths
  4. Avoid solutions suggesting browser-esbuildit's being phased out

Final Recommendation

For most scenarios, targeted configurations (like the main dev-watch solution) provide the optimal balance of flexibility and maintainability. This approach respects Angular 18's builder evolution while solving the /browser folder dilemma cleanly.