Angular CLI and Project Structure: Every File ng new Creates [2026]

Link copied
Angular CLI and Project Structure: Every File ng new Creates [2026]

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 budgets array when your bundle warning fires (a real entry, not just panic)
  • Add a path to assets or styles
  • 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. Add provideHttpClient() to app.config.ts when you need it.
  • Forms — same shape. Import ReactiveFormsModule (legacy) or signal forms (modern) per-component.
  • Animations — opt-in via provideAnimationsAsync().
  • PWA / Service Workerng add @angular/pwa to opt in.
  • SSRng add @angular/ssr to opt in.
  • Material / CDKng add @angular/material if 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:

YouI just ran ng new. What does the app.config.ts file do, and what are the most common providers I’d add to it?
Claude · used 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.

Angular Tutorial · Lesson 1.2
← Previous lesson What is Angular and Where it Fits: A 2026 Developer’s Guide Next lesson → Dependency injection explained (coming soon)

Up next in Angular

More from this topic

View all Angular articles →
Angular

When Angular is launched ?

Link copied When Angular is launched ? When Angular Landed: A History of the Popular Web Framework # Angular, …

Feb 8, 2024 Read →

Enjoyed this article?

Get new Angular tutorials delivered. No spam — just code-first articles when they ship.

Leave a Comment

Your email stays private. Required fields are marked *

Leave a Comment

Your email stays private. Required fields are marked *