In a multi-project Angular CLI workspace, how does ng build decide which project to build, and how do you target one explicitly?
answer
- no initial app at the root
- projects folder by default
- the working directory matters
- some commands run for all
- project:target:configuration
basics
~20 sAn Angular CLI command such as ng build picks the only project with that target, or the project containing the current directory; otherwise it errors. Name the project explicitly, as in ng build admin or ng run admin:build:production.
solid answer
~50 sA multi-project workspace usually starts with `ng new my-workspace --no-create-application`, then `ng generate application shop` and `ng generate application admin`, which land under `newProjectRoot`, `projects/` by default, each with its own entry and targets in `angular.json`. When you run `ng build` without a project, the CLI builds the single project that has a `build` target if there is only one; otherwise it uses the project whose root contains the current working directory; failing both, it stops with "Cannot determine project for command" and lists the candidates. `ng test`, `ng lint` and `ng e2e` behave differently: without a project they run for **every** project that has the target. To be explicit, pass the project positionally, `ng build admin -c staging`, or use `ng run admin:build:staging`. The old `defaultProject` setting was deprecated in Angular CLI 14 and removed in 16.
code
bash · 13 linesng new my-workspace --no-create-application
cd my-workspace
ng generate application shop
ng generate application admin
# explicit project (positional)
ng build admin -c production
# full target specifier: project:target:configuration
ng run shop:build:development
# multi-target command: runs test for every project that has a test target
ng testgo deeper
Recall that ng build admin builds a named project and that ng new --no-create-application starts an empty multi-project workspace.
Explain how the CLI infers the project, why test and lint run for all projects, and the project:target:configuration specifier used by ng run.
Write CI scripts that name projects explicitly, give each project its own configurations, and avoid behaviour that depends on the working directory.
Decide when several applications belong in one workspace, weighing shared dependencies and tooling against coupled upgrades and build times.
## What a multi-project workspace is One `angular.json` can describe several **projects**: applications and libraries that share one `node_modules`, one set of dependency versions and one lint and test setup. It suits a repository that ships, for example, a customer-facing shop and an internal admin console that share a component library. ```bash ng new my-workspace --no-create-application cd my-workspace ng generate application shop ng generate application admin ng generate library ui-kit ``` - `--no-create-application` (the `createApplication` option set to false) creates an empty workspace with no application at the root. - New projects go under `newProjectRoot`, which defaults to `projects`, so the layout becomes `projects/shop`, `projects/admin`, `projects/ui-kit`. - Each project gets its own entry under `projects` in `angular.json`, with its own `root`, `sourceRoot`, `prefix` and targets. ## How a command picks its project For commands that run a single target, such as `ng build`, `ng serve`, `ng deploy` and `ng extract-i18n`, the CLI chooses a project in this order: 1. A project named on the command line, positionally (`ng build admin`) or with `--project`. 2. If exactly one project defines the target, that project. 3. Otherwise, the project whose root directory contains the **current working directory**. 4. Otherwise, it fails with "Cannot determine project for command", explaining that this is a multi-project workspace and listing the projects that support the command. `ng test`, `ng lint` and `ng e2e` are **multi-target** commands: with no project named, they run the target for every project that has it, one after another, so a single `ng test` in the workspace root tests everything. ## Naming project, target and configuration together `ng run` takes a full target specifier: ```bash ng run admin:build # admin's build target, its defaultConfiguration ng run admin:build:staging # with the staging configuration ng run shop:serve:production ``` `ng run` does not accept `--configuration`; the configuration is the third segment of the specifier. The same `project:target:configuration` form appears inside `angular.json`, for example in a serve target's `buildTarget`. ## What each project entry holds | Property | Meaning | |---|---| | `root` | the project's folder, relative to the workspace; empty for an initial app created at the root | | `sourceRoot` | where its sources live, such as `projects/admin/src` | | `projectType` | `application` or `library` | | `prefix` | selector prefix used by `ng generate` for that project | | `architect` | its targets: `build`, `serve`, `test` and any custom ones | Because targets are per project, two applications can use different builders or options without affecting each other, and a library project gets its own build target. ## Several apps, several environments Each project carries its **own** `configurations`, so `shop` can have `production` and `staging` while `admin` has `production` and `internal`. A CI pipeline typically builds them explicitly: ```bash ng build shop -c production ng build admin -c internal ``` Naming the project explicitly in scripts is the robust choice, because inference depends on the working directory and on how many projects happen to define the target today. Adding a second application later would otherwise break a script that relied on there being only one. ## What changed over time | Version | Change | |---|---| | Angular CLI 14 | `defaultProject` in `angular.json` deprecated; the project is inferred from the working directory | | Angular CLI 16 | `defaultProject` removed | | Angular CLI 22 | the inference rules above; multi-target commands run for all projects | Older guides that tell you to set `defaultProject` describe a workspace option that no longer exists. ## Practical tips - Keep shared code in library projects rather than importing across application folders. - Give each application a distinct `prefix` so generated selectors do not collide. - Use `ng config projects.admin.prefix` to inspect or script changes to a single project's settings.
- Why can a CI script that runs plain ng build start failing after someone adds a second application?With one project defining `build`, the CLI picks it automatically. With two, it falls back to the current working directory, and from the workspace root no single project contains it, so the command fails with "Cannot determine project for command". Naming the project in the script avoids depending on the count.
- Why does ng test in the workspace root run the tests of every project?`ng test`, `ng lint` and `ng e2e` are multi-target commands: when no project is named, they collect every project that defines the target and run each in turn. `ng build` and `ng serve` are single-target and need to resolve exactly one project.
saying these in an interview costs you the question
- Set defaultProject in angular.json to choose which app ng build uses.
- ng build without a project name builds every application in the workspace.
- ng run admin:build --configuration staging is the way to pick a configuration.
- All projects in a workspace must share one set of build configurations.
- ng new always creates an application at the workspace root.