02 · The CLI & Project Structure¶
The Angular CLI (@angular/cli, command name ng) is how you create, run, build, test,
generate and upgrade Angular projects. You can build an Angular app without it, but almost
nobody does — the CLI owns the build configuration so that ng update can later migrate it
for you.
Creating a project¶
You do not need to install the CLI globally. npx runs a specific version once:
Without flags, ng new asks a few questions (stylesheet format, whether to enable
server-side rendering, whether to generate AI-assistant configuration files). To accept the
defaults and skip prompts, add --defaults. The options you are most likely to care about:
| Flag | What it does | Default in 22 |
|---|---|---|
--style |
css, scss, sass, less or tailwind |
css |
--ssr |
Adds server-side rendering and prerendering (Level 3, lesson 06) | asked |
--routing |
Generates app.routes.ts and wires the router |
yes |
--test-runner |
vitest or karma |
vitest |
--zoneless |
App does not load zone.js |
yes for new apps |
--inline-template / --inline-style |
Root component uses template: / styles: instead of separate files |
no |
--skip-git, --skip-install |
Skip git init / npm install |
no |
If you prefer a global install (npm install -g @angular/cli), keep in mind that inside a
project the CLI always hands off to the project's local copy in node_modules, so each
project uses the version it was built with.
What was generated¶
Running ng new demo --defaults --ssr=false with Angular CLI 22.2.0 created this tree
(minus node_modules):
demo/
├── .editorconfig
├── .gitignore
├── .prettierrc
├── .vscode/ extensions.json, launch.json, tasks.json
├── angular.json
├── package.json
├── README.md
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.spec.json
├── public/
│ └── favicon.ico
└── src/
├── index.html
├── main.ts
├── styles.css
└── app/
├── app.ts
├── app.html
├── app.css
├── app.spec.ts
├── app.config.ts
└── app.routes.ts
Walking through it from the outside in:
package.json — dependencies. Runtime packages are the @angular/* framework
packages, rxjs and tslib. Development packages include @angular/cli,
@angular/build (the build system), @angular/compiler-cli, typescript (6.0 for
Angular 22), vitest and jsdom for tests. Notice what is not there: zone.js. New
projects are zoneless.
angular.json — the workspace configuration. It declares one project (demo) and
its architect targets: build uses the @angular/build:application builder with
src/main.ts as the entry point, serve uses @angular/build:dev-server, and test
uses @angular/build:unit-test. The production build configuration also declares
budgets — size limits that turn into warnings or errors (500 kB warning / 1 MB error
for the initial bundle by default). Level 4 lesson 01 covers this file in depth.
tsconfig*.json — TypeScript settings. The base file enables options such as
noImplicitReturns and noPropertyAccessFromIndexSignature, and Angular-specific
compiler options under angularCompilerOptions. tsconfig.app.json covers application
code and excludes *.spec.ts; tsconfig.spec.json covers tests and adds the
vitest/globals types so describe/it/expect need no import. There is no
"strict": true line in the generated file because TypeScript 6 turns strict mode on by
default — a parameter without a type fails the build:
src/index.html — the single HTML page. Its <body> contains just <app-root></app-root>,
the root component's selector. <base href="/"> tells the router where the app lives;
change it when deploying under a sub-path (Level 4, lesson 07).
src/main.ts — the entry point:
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));
src/app/app.config.ts — application-wide providers. Generated with
provideBrowserGlobalErrorListeners() (report uncaught errors and unhandled promise
rejections to Angular's ErrorHandler) and provideRouter(routes). You will add
provideHttpClient() here in lesson 09.
src/app/app.ts, app.html, app.css — the root component, split into class,
template and styles. app.spec.ts is its test.
public/ — files copied as-is to the build output (favicon, robots.txt, images you
reference by URL).
The four commands you will use every day¶
ng serve # dev server with rebuild on save, http://localhost:4200 by default
ng build # production build into dist/<project>/browser
ng test # run unit tests (Vitest), in watch mode when run interactively
ng generate ... # scaffold components, services, guards, pipes, and more
Inside a project you can run them as npx ng ... or through the npm scripts the CLI
added (npm start, npm run build, npm test).
Here is ng build on the Level 1 project app — note the lazy chunk files for routes
that are loaded on demand (lesson 08):
Initial chunk files | Names | Raw size | Estimated transfer size
chunk-CFBDKLSF.js | - | 160.35 kB | 47.02 kB
chunk-VDKBJWIX.js | - | 95.29 kB | 24.11 kB
main-YHP7CJVG.js | main | 5.35 kB | 1.87 kB
styles-5INURTSO.css | styles | 0 bytes | 0 bytes
| Initial total | 260.99 kB | 73.00 kB
Lazy chunk files | Names | Raw size | Estimated transfer size
chunk-ZTOYL6TL.js | book-search | 2.25 kB | 1.03 kB
chunk-OUVVJBSL.js | book-detail | 878 bytes | 878 bytes
Application bundle generation complete. [1.463 seconds]
The hashes in file names (main-YHP7CJVG.js) change whenever content changes, so you
can cache these files forever on a CDN.
Generating code¶
With CLI 22.2 that produced:
CREATE src/app/book-card/book-card.css (0 bytes)
CREATE src/app/book-card/book-card.spec.ts (547 bytes)
CREATE src/app/book-card/book-card.ts (196 bytes)
CREATE src/app/book-card/book-card.html (24 bytes)
CREATE src/app/books.spec.ts (315 bytes)
CREATE src/app/books.ts (76 bytes)
Useful flags: --inline-template (-t) and --inline-style (-s) to keep everything
in one .ts file, --skip-tests to omit the spec, --flat to avoid creating a folder,
and --dry-run to see what would be created without touching disk.
Other schematics you will meet later in this course: guard, interceptor, resolver,
pipe, directive, environments, library and web-worker.
Naming conventions (the 2025 style guide)¶
Before Angular 20, generated files were named book-card.component.ts with a class
called BookCardComponent. The current style guide drops the type suffix: the file is
book-card.ts and the class is BookCard. Both work — it is only a convention — and
ng new --file-name-style-guide=2016 keeps the old style. Existing projects upgraded with
ng update keep their old names; nothing is renamed for you.
How It Actually Works¶
ng is a thin command dispatcher. Each command maps to a builder configured in
angular.json. ng build runs @angular/build:application, which does roughly this:
- TypeScript + Angular compilation. The Angular compiler plugin type-checks your
.tsfiles and your templates, and emits JavaScript with templates compiled into instruction functions (see lesson 01). - Bundling with esbuild. The emitted modules are bundled, dynamic
import()s become separate lazy chunks, unused code is tree-shaken, and output is minified. - Styles and assets. Global styles (
src/styles.css) and component styles are processed; files inpublic/are copied. - Index generation.
src/index.htmlis rewritten to reference the hashed bundles. - Budget check. Output sizes are compared with the budgets in
angular.json.
ng serve uses the same compilation pipeline but serves files from memory through a
Vite-based dev server, rebuilding incrementally on save. ng test compiles your spec
files with the same Angular compiler and hands them to Vitest running in a jsdom
environment (Level 3, lesson 07). That shared pipeline is why a template error shows up
identically in serve, build and test.
Schematics — the code generators behind ng generate, ng new, ng add and the
migrations run by ng update — operate on a virtual file tree. They compute all the
changes first and only write them to disk at the end, which is why --dry-run can show
you exactly what would happen.
Common mistakes¶
- Mixing CLI versions. A global
ngfrom an older major can create a project with outdated defaults. Usenpx @angular/cli@22 new ...to be explicit. - Editing files in
dist/. They are regenerated on every build. Change the source. - Putting images in
src/assets/because an old tutorial said so. New projects usepublic/; files there are served from the site root (/logo.svg, not/assets/logo.svg). - Ignoring budget warnings. They are the cheapest performance alarm you have.
- Committing
.angular/cache. It is a local build cache and is already in the generated.gitignore.
Exercise¶
- Create a new project with
npx @angular/cli@22 new sandbox --defaults. - Run
ng buildand record the initial total size it reports. - Generate a component called
greetingwith inline template and style, and without a spec file. Which single file was created? - Use
<app-greeting />inapp.html. Runng buildagain — it fails. Read the error, then fix it by addingGreetingto the root component'simportsarray. (Lesson 03 explains why this is required.) - Open
angular.json, lower the initial budget'smaximumErrorto100kB, and build again. Note the error, then put it back.