Project Structure
When you create a new Angular project with the CLI, it generates a well-organized directory structure. Understanding every file and folder will help you navigate large projects confidently and know exactly where to put new code.
Let's explore the structure of a freshly scaffolded Angular 17+ project with standalone components.
Top-Level Directory Overview
my-angular-app/ ├── .angular/ # Angular CLI cache (git-ignored) ├── .vscode/ # VS Code settings (optional) ├── node_modules/ # npm dependencies (git-ignored) ├── public/ # Static assets (Angular 17+) │ └── favicon.ico ├── src/ # Your application source code │ ├── app/ # Application code (components, services, etc.) │ ├── assets/ # Images, fonts, JSON files (older Angular) │ ├── index.html # Root HTML page │ ├── main.ts # Application entry point │ └── styles.css # Global CSS styles ├── .editorconfig # Editor formatting rules ├── .gitignore ├── angular.json # Angular CLI workspace configuration ├── package.json # npm dependencies and scripts ├── package-lock.json # Exact dependency versions ├── tsconfig.json # Base TypeScript configuration ├── tsconfig.app.json # TypeScript config for the app └── tsconfig.spec.json # TypeScript config for tests
The src/ Directory
Everything you write lives inside src/. Here is what each file does:
File | Purpose |
|---|---|
src/index.html | The single HTML file served to the browser. Contains <app-root> where Angular mounts. |
src/main.ts | Entry point — bootstraps the Angular application. |
src/styles.css | Global styles applied across the entire app. |
src/app/ | Your feature code: components, services, routes, etc. |
public/favicon.ico | Browser tab icon (Angular 17+ puts public assets here). |
<!-- src/index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>MyAngularApp</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> <!-- Angular renders here -->
</body>
</html>// src/main.ts — bootstraps the app
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));The src/app/ Directory
src/app/ ├── app.component.ts # Root component (class) ├── app.component.html # Root component template ├── app.component.css # Root component styles ├── app.component.spec.ts # Root component unit tests ├── app.config.ts # Application-level providers (DI config) └── app.routes.ts # Route definitions
// src/app/app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
title = 'my-angular-app';
}// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
],
};// src/app/app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
// Define your routes here
// { path: 'home', component: HomeComponent },
];Recommended Feature-Based Structure
As your app grows, organize code into feature folders. Each feature folder contains all the code related to one feature or domain:
src/app/ ├── core/ # Singleton services, guards, interceptors │ ├── services/ │ │ ├── auth.service.ts │ │ └── api.service.ts │ ├── guards/ │ │ └── auth.guard.ts │ └── interceptors/ │ └── auth.interceptor.ts │ ├── shared/ # Reusable components, pipes, directives │ ├── components/ │ │ ├── button/ │ │ └── modal/ │ ├── pipes/ │ │ └── truncate.pipe.ts │ └── directives/ │ └── tooltip.directive.ts │ ├── features/ # Feature modules / pages │ ├── home/ │ │ ├── home.component.ts │ │ ├── home.component.html │ │ └── home.component.css │ ├── products/ │ │ ├── product-list/ │ │ │ ├── product-list.component.ts │ │ │ └── product-list.component.html │ │ ├── product-detail/ │ │ │ ├── product-detail.component.ts │ │ │ └── product-detail.component.html │ │ └── product.service.ts │ └── auth/ │ ├── login/ │ └── register/ │ ├── models/ # TypeScript interfaces and types │ ├── user.model.ts │ └── product.model.ts │ ├── app.component.ts ├── app.config.ts └── app.routes.ts
angular.json — The Configuration Hub
angular.json is the workspace configuration file. It controls how the CLI builds, serves, and tests your project:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"my-angular-app": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "css",
"standalone": true
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/my-angular-app",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"styles": ["src/styles.css"],
"assets": [{ "glob": "**/*", "input": "public" }]
}
}
}
}
}
}tsconfig.json — TypeScript Configuration
// tsconfig.json — base config
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"strict": true, // enables all strict type checks
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"isolatedModules": true,
"esModuleInterop": true,
"experimentalDecorators": true, // required for @Component, @Injectable, etc.
"moduleResolution": "bundler",
"target": "ES2022",
"module": "ES2022",
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true // type-check component templates
}
}strictTemplates: true enables full TypeScript type checking inside HTML templates — catching bugs like passing the wrong type to an @Input. Always leave this enabled.package.json — Scripts and Dependencies
{
"name": "my-angular-app",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"dependencies": {
"@angular/animations": "^17.3.0",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/core": "^17.3.0",
"@angular/forms": "^17.3.0",
"@angular/platform-browser": "^17.3.0",
"@angular/router": "^17.3.0",
"rxjs": "~7.8.0",
"zone.js": "~0.14.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.0",
"@angular/cli": "^17.3.0",
"@angular/compiler-cli": "^17.3.0",
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0",
"karma": "~6.4.0",
"typescript": "~5.4.2"
}
}Environment Files
Angular uses environment files for configuration that differs between development and production (API URLs, feature flags, analytics keys, etc.):
src/app/environments/ ├── environment.ts # development defaults └── environment.prod.ts # production overrides (swapped at build time)
// src/app/environments/environment.ts
export const environment = {
production: false,
apiUrl: 'http://localhost:3000/api',
analyticsKey: '',
};
// src/app/environments/environment.prod.ts
export const environment = {
production: true,
apiUrl: 'https://api.myapp.com',
analyticsKey: 'UA-XXXXXXXX',
};// Usage in a service
import { environment } from '../environments/environment';
@Injectable({ providedIn: 'root' })
export class ApiService {
private baseUrl = environment.apiUrl; // automatically correct per build
}File Naming Conventions
File type | Naming convention | Example |
|---|---|---|
Component | kebab-case.component.ts | user-profile.component.ts |
Template | kebab-case.component.html | user-profile.component.html |
Styles | kebab-case.component.css/scss | user-profile.component.scss |
Test | kebab-case.component.spec.ts | user-profile.component.spec.ts |
Service | kebab-case.service.ts | user.service.ts |
Guard | kebab-case.guard.ts | auth.guard.ts |
Pipe | kebab-case.pipe.ts | truncate.pipe.ts |
Directive | kebab-case.directive.ts | highlight.directive.ts |
Model/Interface | kebab-case.model.ts | user.model.ts |
Route config | kebab-case.routes.ts | products.routes.ts |
ng generate. Following them makes your codebase predictable and easy to navigate.Key Takeaways
src/main.ts bootstraps the app; src/index.html is the HTML shell
src/app/ holds all application code organized by feature
angular.json configures how the CLI builds and serves the app
tsconfig.json enables strict TypeScript and Angular template type checking
Feature-based structure (core/shared/features) scales well for large apps
Environment files separate config for development and production builds
Follow kebab-case.type.ts naming — the CLI does this automatically