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-esbuild – it'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.