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:
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:
- Your deployment pipeline expects flat directory structures
- You need real-time builds (
--watch
) to output directly to a specific location - 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
- Create a new configuration in
angular.json
under your project's buildconfigurations
:
// 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
}
}
}
}
}
}
}
- Execute the build using the new configuration:
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 thebase
path - The dedicated
dev-watch
configuration keeps yourdevelopment
settings pristine - Angular CLI properly merges inherited properties with local overrides
Alternative Solutions
1. Global Configuration Change (In angular.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
"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
- Prefer configurations over CLI flags for environment-specific settings
- Leverage
inherits
to reduce configuration duplication - Test with
--verbose
when modifying output paths - 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.