Angular CLI and Project Structure: Every File ng new Creates [2026]
An Angular project starts with one command and ends with about thirty files you did not write. Most tutorials gloss over what those files do, which means the first time something breaks, you do not know where to look. This lesson is the opposite — we install the Angular CLI, run ng new, and walk through every file the scaffold creates, in the order you will encounter them.
This is lesson 1.2 of the Angular Tutorial. It assumes you know what Angular is at a high level (covered in lesson 1.1) and have Node.js 20+ installed on your machine. We will not write any Angular code yet — just understand the surface area the framework gives you for free.
Installing the Angular CLI #
The Angular CLI is a Node.js package called @angular/cli. You install it once, globally, and it gives you the ng command that drives every Angular project on your machine.
npm install -g @angular/cli
That lands the latest stable release. To verify:
ng version
You should see Angular CLI 21.x or later (the curriculum targets v21/v22). If you are on a corporate machine without global-install privileges, npx @angular/cli new my-app works for one-off scaffolding without installing anything globally.
Three details worth knowing day one:
| Concern | Detail |
|---|---|
| Node version | Angular 21+ requires Node 20 LTS or newer. Older Node versions fail at install time. |
| Package manager | The CLI defaults to npm, but supports pnpm, yarn, and bun via ng config cli.packageManager. Pick one per machine and stick with it. |
| Version pinning per project | Once ng new runs, the CLI version is pinned in package.json under @angular/cli. The global CLI just delegates to the project's local copy. Two projects can use two CLI versions side by side. |
That last point catches people. The global ng command is a thin wrapper. Inside a project, the project's local Angular CLI version is the one actually running. Upgrade the project with ng update, not by reinstalling the global package.
Running ng new #
With the CLI installed, you create a new project with one command:
ng new my-app
The CLI prompts you for a few choices. The 2026 defaults are sensible — accept them unless you have a reason:
| Prompt | What to pick | Why |
|---|---|---|
| Which stylesheet format? | CSS | Plain CSS is the lowest-friction default. Pick SCSS only if your team mandates it. |
| Server-Side Rendering (SSR)? | No for a first project | You can add SSR later with ng add @angular/ssr. Skip until you need it. |
| Server routing & prerendering? | No for a first project | Tied to SSR — same answer. |
| Use AI-assisted setup? | No | A v22 prompt. Manual setup is fine and you learn more. |
The CLI scaffolds the project, runs npm install, and initializes a git repo. After 30–60 seconds you have a working app.
If you want to skip the prompts in CI or for repeatable scaffolding, every prompt has a flag:
ng new my-app --style=css --ssr=false --routing --skip-git
The folder tour #
A fresh ng new my-app produces this structure (formatted for clarity):
my-app/
├── .editorconfig
├── .gitignore
├── .vscode/ ← VS Code launch + tasks for ng commands
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
├── angular.json ← Workspace config (build, serve, test)
├── package.json
├── package-lock.json
├── tsconfig.json ← Base TS config
├── tsconfig.app.json ← App-specific TS config
├── tsconfig.spec.json ← Test-specific TS config
├── node_modules/ ← gitignored
├── public/ ← Static assets served as-is
│ └── favicon.ico
└── src/ ← Your app's source code
├── index.html ← The HTML shell
├── main.ts ← Bootstrap entry point
├── styles.css ← Global styles
└── app/ ← Your components live here
├── app.config.ts ← Root ApplicationConfig
├── app.routes.ts ← Route table
├── app.ts ← Root AppComponent class
├── app.html ← Root AppComponent template
├── app.css ← Root AppComponent styles
└── app.spec.ts ← Root AppComponent tests
That is the entire surface area of a fresh Angular app. We will walk each one in turn.
Files you will touch every day #
src/main.ts #
The entry point. Three meaningful lines:
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));
bootstrapApplication is the standalone-API replacement for the older platformBrowser().bootstrapModule(AppModule) ceremony. It takes a root component (App) and an ApplicationConfig (everything you want available globally — providers for the router, HTTP, animations, etc.). No NgModule in sight.
We will look at app.config.ts next; for now just notice that main.ts is short on purpose. You will rarely edit it after the first day.
src/app/app.config.ts #
The root provider configuration:
import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideZonelessChangeDetection(),
provideRouter(routes),
],
};
This is where every provideX() function lands — router, HTTP client, animations, hydration, your own services. Lesson 1.6 covers ApplicationConfig in depth; for now, know that this is the spot you reach for when adding cross-cutting capabilities like HTTP or routing to your app.
src/app/app.routes.ts #
An empty array, ready for you to fill:
import { Routes } from '@angular/router';
export const routes: Routes = [];
When you have a route to declare, you push a { path, component } (or loadComponent for lazy routes) here. Module 5 covers the full router surface.
src/app/app.ts + app.html + app.css #
The root AppComponent. The 2026 scaffold splits it into three files (class, template, styles) by default — a v18 change. You will typically edit app.html to add your shell layout (nav bar, sidebar, <router-outlet>), and let app.ts stay mostly empty for a long time.
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.html',
styleUrl: './app.css',
})
export class App {
protected title = 'my-app';
}
Note imports: [RouterOutlet] — that is the standalone-component way of saying "this template uses <router-outlet>." Module 2 covers components in depth.
Files you will configure occasionally #
angular.json #
The workspace manifest. Defines projects (most apps have one, but a workspace can hold many), and for each project: the build target, serve target, test target, asset paths, budget warnings, and more.
Day one you will not touch it. The first time you need to:
- Increase the
budgetsarray when your bundle warning fires (a real entry, not just panic) - Add a path to
assetsorstyles - Swap the dev-server port (
serve.options.port) - Configure file replacements for production (
fileReplacements)
Keep it tidy. angular.json is parsed by the CLI on every command; a malformed JSON file is a slow productivity tax.
package.json #
Standard Node.js manifest. The Angular-specific section is the dependency block — @angular/core, @angular/router, @angular/forms, etc. All Angular packages share a version number that tracks the framework release. ng update keeps them in lockstep.
The scripts block has three you will use constantly:
{
"scripts": {
"start": "ng serve",
"build": "ng build",
"test": "ng test"
}
}
tsconfig.json + tsconfig.app.json + tsconfig.spec.json #
Three TypeScript configs. The split exists because the app build and the test build want slightly different TypeScript options.
| File | Used by | What you tune here |
|---|---|---|
tsconfig.json |
All other tsconfigs extend this | Strictness flags, path aliases |
tsconfig.app.json |
ng build and ng serve |
App-only includes, output paths |
tsconfig.spec.json |
ng test (Vitest) |
Test type roots, spec file globs |
The defaults are reasonable. The first one you will edit is the base tsconfig.json — usually to add paths for cleaner imports (@app/services/* instead of ../../services/*).
public/ #
Files in public/ are copied verbatim to the build output and served at the root URL. Drop a logo, favicons, robots.txt, or static images here. Anything you reference with /favicon.ico lives here.
This replaced the older src/assets/ convention in v18. Both still work, but public/ is the default.
src/index.html #
The HTML shell. The browser loads this first; Angular renders into the <app-root> element inside it. You usually edit it for <meta> tags (title, description, viewport), webfont links, and analytics snippets.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MyApp</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
The <app-root></app-root> placeholder is replaced at runtime by your App component's template.
The daily-driver commands #
Four ng commands cover 90% of day-to-day work:
| Command | What it does | When you run it |
|---|---|---|
ng serve |
Start the dev server with hot-reload at localhost:4200 |
Every morning |
ng build |
Production build into dist/ (or --configuration development for unminified) |
Before deploying |
ng test |
Run the unit-test suite (Vitest, since v21) | Before pushing |
ng generate <kind> (or ng g) |
Scaffold a component / service / pipe / directive | A few times per feature |
The generate command is the workhorse. Examples:
ng g component user-profile # creates src/app/user-profile/...
ng g service api # creates src/app/api.service.ts
ng g directive hover-glow # creates src/app/hover-glow.directive.ts
ng g pipe currency-symbol # creates src/app/currency-symbol.pipe.ts
Each generator scaffolds the file, its spec, and updates references where needed. It is faster than typing the file out, and the conventions stay consistent across your team.
Starting the dev server #
Once the scaffold is in place:
cd my-app
ng serve
The server starts at http://localhost:4200. The default landing page is intentionally minimal — Angular branding plus links to the docs.
The dev server uses esbuild for the bundler (since v17) and Vite for the dev pipeline (since v18). Cold start is a few seconds; HMR is sub-second. Lesson 1.5 covers what the build pipeline actually does; for now, just know that the modern Angular dev experience is fast.
What's not there #
The scaffold is deliberately minimal. Things you do not get in a fresh ng new and will install later as needed:
- HTTP client — included in
@angular/common, but not provided by default. AddprovideHttpClient()toapp.config.tswhen you need it. - Forms — same shape. Import
ReactiveFormsModule(legacy) or signal forms (modern) per-component. - Animations — opt-in via
provideAnimationsAsync(). - PWA / Service Worker —
ng add @angular/pwato opt in. - SSR —
ng add @angular/ssrto opt in. - Material / CDK —
ng add @angular/materialif you want them.
The ng add command is its own pattern: it installs the package, modifies app.config.ts to register providers, and updates angular.json as needed. It is one-shot setup, not boilerplate.
Common gotchas #
| Symptom | Cause | Fix |
|---|---|---|
Could not find module "@angular/core" |
You ran ng serve outside the project root |
cd into the project first |
| Bundle warning at build time | Your code grew past the budget in angular.json |
Either fix the bloat (lesson 8.5) or raise the budget |
ng serve fails on port 4200 |
Another process is on 4200 (often a previous ng serve you forgot) |
ng serve --port 4201 or kill the previous process |
ng update complains about peer deps |
Some installed package is a major version behind | Update the package first, then re-run ng update @angular/core |
| New file generated under wrong folder | You ran ng g from a deeper directory |
The CLI generates relative to the current dir. Run from src/app/ or pass a path: ng g component features/user-profile |
What's next #
In lesson 1.3 we walk through dependency injection — the system that wires your services and shared state to your components. It is one of Angular's most opinionated decisions and the one that pays the most dividends on a real team. Then lessons 1.4 through 1.7 cover TypeScript essentials, the build pipeline, application bootstrap, and the DI deep-dive.
By the end of Module 1 you will have an Angular app running, understand every line of its scaffold, know how to add a service or a route, and be ready for the Components & Templates module — where most of the day-to-day code lives.
Try it yourself #
The shortest end-to-end check that everything is wired up correctly is two commands:
ng new hello-angular --style=css --ssr=false --skip-git
cd hello-angular
ng serve --open
The --open flag launches your browser at localhost:4200 automatically. You should see the default landing page with the Angular logo. If an AI assistant is wired to Angular's MCP server, you can also ask:
ng new. What does the app.config.ts file do, and what are the most common providers I’d add to it?get_best_practicesapp.config.ts defines the root ApplicationConfig — the providers your whole app sees. The fresh scaffold ships with provideZonelessChangeDetection() and provideRouter(routes). The four you will most commonly add next:•
provideHttpClient() — when you need to call an API•
provideAnimationsAsync() — when you add Angular Material or your own animations•
provideClientHydration() — when you add SSR• Custom services via
{ provide: TOKEN, useValue: ... }All of them live in the
providers array. There is no NgModule to worry about.You now have a running Angular app and know what every file in it does. Lesson 1.3 picks up the dependency-injection thread — the most consequential single decision in the framework.
Up next in Angular
More from this topic
Enjoyed this article?
Get new Angular tutorials delivered. No spam — just code-first articles when they ship.


