
Quick answer: Install the CLI with npm install -g @angular/cli (or use npx), then run ng new my-app and ng serve. Angular’s project is organised around one folder, src/app, where every component, service and route lives. Learning four CLI commands — new, generate, serve and build — is enough to work productively.

Table of Contents

Check Node first
Angular needs a current Node.js LTS. Run node -v; if it fails or reports an old version, install the LTS release from nodejs.org. Every modern Angular release requires a recent Node, and the CLI will tell you plainly when yours is too old.
Create the project with the Angular CLI
npm install -g @angular/cli
ng new my-app --defaults --routing --style=css
cd my-app
ng serveThe --defaults flag skips the interactive prompts and accepts today’s sensible choices: standalone components, strict TypeScript and Vitest for testing. --style=css keeps plain CSS unless your team uses something else. The dev server starts on http://localhost:4200 and reloads on every save. If you have never created a project before, our step-by-step Angular install guide covers the same ground with screenshots of each prompt.
The files that matter
A new project creates dozens of files, but you only touch a handful at first. Everything you write lives in src/app.
| Path | What it does |
|---|---|
src/main.ts | Bootstraps the app — rarely edited |
src/app/app.component.ts | Root component class |
src/app/app.component.html | Root template — start here |
src/app/app.routes.ts | Route table for the router |
src/app/app.config.ts | Application-wide providers |
angular.json | Build and serve configuration |
Notice there is no app.module.ts. New projects boot through main.ts using bootstrapApplication, so a single root component replaces the old root module. If a tutorial mentions AppModule, it predates the standalone default.

The four Angular CLI commands you will use daily
ng generate component product-card
ng generate service cart
ng generate guard auth
ng buildng generate (or its short form, ng g) scaffolds a component, service, guard, pipe or directive with the files and imports already wired. Generating rather than hand-creating files keeps naming and folder conventions consistent across the team. Then ng build produces an optimised bundle in dist/ when you are ready to deploy.
One useful habit: run ng serve in one terminal and keep it running while you work. The dev server rebuilds incrementally, so a save shows up in the browser in well under a second.
Where to go next
With a running project, the next step is understanding how it is put together — how components, services and providers relate. Continue with our guide to Angular’s architecture and standalone components.
Prefer to learn the CLI and project layout with someone guiding you through a real build? Ampersand Academy runs one-to-one Angular training from setup to deployment.
Angular CLI habits that keep a project tidy
Let the Angular CLI own the boilerplate. The generator exists because hand-written Angular files drift out of sync: a component created by copying a folder misses the standalone import, a service left without its decorator breaks injection, and a module name spelled one way in the CLI and another in the router wastes an afternoon. Use ng generate for every component, service, pipe and guard instead of duplicating files, and the Angular CLI will place the file in the right folder, write the import, and keep naming conventions uniform across the team. The seconds saved per file add up, but the consistency is the real benefit.
Keep naming predictable. A flat, feature-first structure such as src/app/orders holding the orders component, service, routes and tests reads better than a global components folder that grows without bound. When a feature needs a shared utility, promote it deliberately rather than importing across folders casually, because import paths are the map other developers navigate by. The Angular CLI does not enforce this structure, so the discipline has to be yours: decide the convention once, generate files into it, and review pull requests for structure as well as logic. New contributors should be able to guess where a file lives before they open the tree.
Separate the commands you run while writing from the ones you run when shipping. ng serve is for the loop of save, reload and check; it rebuilds quickly but serves unoptimised bundles and does not prove anything about production. ng build is the real test, because tree shaking, budget checks and the strict template compiler all run at that point and failures there are the ones that reach users. A useful habit is to run the build before every push even when the change looked trivial: the Angular CLI is fast enough that the check costs seconds, and it catches template type errors the dev server tolerates.
Read the CLI output instead of scrolling past it. The Angular CLI prints useful warnings in normal operation — a budget exceeded, a component that is not standalone, an unused import flagged by linting — and each one corresponds to something that will cost more time later. Budgets in particular are easy to ignore until a route bundle has doubled; raising the budget without looking at what grew is how applications become slow in small, invisible steps. Treat these messages as part of the compiler rather than as noise, and fix them in the same session they appear, while the change that caused them is still in your head.
Run the test and lint commands on the same cadence as the build. The Angular CLI wires up the runner chosen at project creation, so ng test executes the same way for everyone, with no local configuration to drift. Keeping tests beside the files they cover makes them cheap to run, and a red suite after a small edit points directly at the edit. Add a single npm script that runs lint, test and build in order if you want one command before pushing; the point is that verification becomes a habit attached to finishing a change, not a separate activity you schedule for later, when the context that produced the bug is already gone.

Keeping the Angular CLI version under control
Most breakage in Angular projects traces to a mismatch between the globally installed Angular CLI and the local one pinned in package.json. When you run ng serve, Angular resolves the local binary first, so the global version is largely irrelevant after project creation — but it does matter when you scaffold a new project. Run ng version inside the project root; both the global and local versions print side by side.
Update the local Angular CLI alongside the framework itself. Angular ships a migration command for exactly this:
ng update @angular/core @angular/cling update @angular/core @angular/cli
That single command updates the packages, rewrites breaking API calls via automated migrations, and adjusts angular.json where needed. Running it early, on each major release, costs far less than skipping two or three versions and untangling the combined diff later.
After an update, commit package-lock.json immediately. That locks every contributor to the same resolved tree and prevents the “works on my machine” version drift that wastes hours in code review.
What Angular CLI schematics are and when to write one
Every ng generate call runs a schematic — a small program that reads options, renders templates, and writes files. The Angular CLI ships a default schematic collection, but you can install or author custom ones. Understanding this layer explains behaviour that otherwise looks arbitrary.
Third-party libraries frequently ship their own schematics. Running ng add @angular/material does not just install the npm package; it runs a schematic that patches app.config.ts, adds the animations provider, and imports the default theme into your global stylesheet. You get a working integration, not a raw install. The same workflow installs Angular’s own renderer: ng add @angular/ssr sets up the server bundle, as the Angular SSR and hydration guide explains.
Writing a custom schematic makes sense when your team creates the same file pattern repeatedly — a feature folder with a component, a service, a routes file, and a barrel export. The Angular CLI can scaffold that entire structure from one command, enforcing the team convention automatically.
A minimal schematic lives in a separate workspace package. Point the Angular CLI at it with the --collection flag or register it in angular.json under cli.schematicCollections. Keep custom schematics small and focused; a schematic that generates too much becomes harder to maintain than the files it saves.
Checking a third-party schematic before it runs
Schematics write files and modify existing ones. Before running ng add for an unfamiliar package, pass the --dry-run flag. The Angular CLI prints every planned file change without touching the disk:
ng add some-library --dry-runng add some-library --dry-run
Review the output. If it touches files you did not expect — a global style, an environment file, or the root index.html — you know to read the library’s changelog before committing. Dry-run costs nothing and prevents surprises in version control.
Build targets, configurations, and the environment file pattern
The Angular CLI build system exposes named configurations defined in angular.json. The default project ships with production and development. You invoke them with:
ng build --configuration=staging
ng serve --configuration=stagingng build --configuration=staging
ng serve --configuration=staging
Each configuration can override any build option: API base URL via file replacement, source maps, optimisation level, and budget thresholds. The file replacement pattern swaps src/environments/environment.ts for src/environments/environment.staging.ts at build time, so the right constants reach the bundle without runtime conditionals cluttering the source.
Add a configuration rather than branching inside component code. A component that reads environment.apiUrl stays clean; a component that checks if (environment.staging) accumulates special cases that are hard to test and easy to forget.
Budget thresholds sit inside each configuration block. Tighten them for production and leave them looser for development. When the Angular CLI reports a budget exceeded in CI but not locally, the cause is almost always that the local developer ran the development configuration, which has no budget constraint, while CI runs production.
The build flags that matter most in CI
Two flags change behaviour enough to affect CI reliability. First, --no-progress suppresses the animated progress output that pollutes log files on most CI platforms. Second, --stats-json writes a webpack stats file to dist/ that tools like webpack-bundle-analyzer read to produce a visual bundle map — useful when a budget alert fires and you need to find what grew.
Neither flag belongs in everyday local use, so keep them in a dedicated CI npm script rather than baking them into the default. The Angular CLI reads them correctly from the command line without any angular.json change.
Debugging Angular CLI build errors without guessing
Template type errors are the class of Angular CLI error that surprises developers most. The dev server may tolerate an incorrect property binding at runtime, because the browser quietly ignores unknown properties, but ng build runs the strict template compiler and fails the build. When you see an error like TS2339: Property 'userName' does not exist on type 'UserComponent', the fix is in the component class, not the template or the build config.
A common pitfall: renaming a property in the class without updating every template reference. TypeScript catches class-to-class references immediately. Template references only surface during a build or with a language-service-enabled editor. The Angular CLI’s strict mode is doing you a favour; disabling strictTemplates in tsconfig.json silences the error but hides a real bug.
For errors that print a long stack trace, read from the bottom up. The Angular CLI wraps lower-level errors in its own output layer, so the root cause — a missing peer dependency, a circular import, or a malformed decorator — sits near the bottom, not the top. Copying only the top line into a search engine usually returns results about the wrapper, not the cause.
Circular dependency warnings from the Angular CLI are soft by default but become failures when the cycle is deep enough to break lazy loading. Treat every circular import warning as a structural defect. The fix is almost always moving a shared type or function into a dedicated utility file that neither importing module owns.
Using the Angular CLI in a multi-project workspace
A single Angular CLI workspace can host multiple projects: a main application, one or more secondary applications, and any number of libraries. Running ng new my-workspace --no-create-application creates the workspace shell without a default app, then you add projects explicitly:
ng generate application admin-portal
ng generate library ui-kitng generate application admin-portal
ng generate library ui-kit
Each project gets its own entry in angular.json and its own tsconfig. The Angular CLI routes build and serve commands to the right project via the --project flag or the defaultProject key. Libraries build to a local dist/ folder, and applications reference them through tsconfig path aliases rather than npm.
The multi-project layout pays off when two applications share a component library but need separate deployment pipelines. It avoids publishing to npm for every internal change and keeps the shared code visible in the same repository as its consumers. The cost is that the workspace angular.json grows large; keep each project’s configuration minimal and rely on the Angular CLI defaults wherever possible.
One practical pitfall: running ng build at the workspace root without --project builds the default project only. In CI, always name the project explicitly to avoid building the wrong target and deploying a stale bundle. Make the project name part of every CI command, and document it in the repository readme so new contributors do not discover the problem at 11pm before a release.
Library projects require a separate build step before the consuming application can see changes. During active development of both the library and the application together, the Angular CLI can watch the library continuously:
ng build ui-kit --watchng build ui-kit --watch
Run that in a second terminal alongside ng serve. The application picks up rebuilt library output automatically without a restart. This workflow mirrors what the article describes for the main dev server — one terminal per long-running process, both left running while you work.
Frequently asked questions
What Node version does Angular need?
A current Node.js LTS release. Install it from nodejs.org if node -v fails or shows an old version, because every modern Angular release requires a recent Node.
Why is there no app.module.ts in my project?
New Angular projects are standalone by default. The app boots from main.ts with bootstrapApplication and a root component, so a root NgModule is no longer created.
What is the difference between ng serve and ng build?
ng serve runs a development server with live reload for daily work. ng build produces an optimised production bundle in the dist folder for deployment.
Where do I write my code in an Angular project?
Almost everything lives in src/app. Components, services, guards and routes go there, and the CLI places new files in the right folder for you.
Can I use JavaScript instead of TypeScript in Angular?
No. Angular is written in TypeScript and its decorators, templates and tooling depend on it. You can write minimal type annotations as a beginner, but the language is TypeScript.
Last updated on · Written by Dinesh Kumar R

