Angular Project File Structure

Understand the main files and folders in an Angular workspace and how to organize components, features, services, routes, models, shared code, assets, configuration, and tests.

Lesson content

Angular Project File Structure An Angular workspace contains configuration files, source code, static assets, dependencies, tests, applications, and libraries. Basic Structure my-app/ │ ├── public/ ├── src/ │ ├── app/ │ ├── index.html │ ├── main.ts │ └── styles.css │ ├── angular.json ├── package.json ├── package-lock.json ├── tsconfig.json ├── tsconfig.app.json ├── tsconfig.spec.json └── node_modules/ Easy Formula Angular Workspace = Configuration Files + Source Code + Static Files + Dependencies + Tests Workspace-Level Files File or Folder Purpose angular.json Angular CLI build, serve, test, assets, and project configuration package.json Project scripts and npm dependencies package-lock.json Stores exact installed package versions tsconfig.json Base TypeScript configuration tsconfig.app.json TypeScript configuration for application code tsconfig.spec.json TypeScript configuration for tests node_modules/ Installed npm packages public/ Static files copied directly during the build src/ Application source code README.md Project documentation and setup instructions .gitignore Files and folders Git should not track .editorconfig Shared editor formatting settings angular.json The angular.json file contains workspace-level and project-level Angular CLI configuration. It commonly controls: Build configuration Development server configuration Testing configuration Global styles Static assets Output paths Development and production configurations { "projects": { "my-app": { "projectType": "application", "sourceRoot": "src", "architect": { "build": { "options": { "outputPath": "dist/my-app", "index": "src/index.html", "browser": "src/main.ts", "styles": [ "src/styles.css" ] } } } } } } package.json The package.json file contains npm scripts and project dependencies. { "scripts": { "start": "ng serve", "build": "ng build", "test": "ng test" }, "dependencies": { "@angular/core": "...", "@angular/common": "...", "@angular/router": "...", "rxjs": "..." }, "devDependencies": { "@angular/cli": "...", "typescript": "..." } } Common Commands npm start npm run build npm test src Folder The src folder contains the main application source files. src/ │ ├── app/ ├── index.html ├── main.ts └── styles.css main.ts The main.ts file is the application entry point. A standalone Angular application commonly starts with bootstrapApplication() . import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; import { appConfig } from './app/app.config'; bootstrapApplication( AppComponent, appConfig ).catch(error => console.error(error) ); Startup Flow main.ts ↓ bootstrapApplication() ↓ AppComponent ↓ Application Starts index.html The index.html file is the main browser page that hosts the Angular application. <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title> My Application </title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1" > </head> <body> <app-root></app-root> </body> </html> The <app-root> element matches the selector of the root Angular component. styles.css The styles.css file contains global styles available throughout the application. html, body { margin: 0; font-family: Arial, sans-serif; } * { box-sizing: border-box; } Component-specific styles should normally remain in the component stylesheet. public Folder The public folder stores static files that are copied without application processing. public/ │ ├── images/ │ ├── logo.png │ └── banner.jpg │ ├── icons/ └── config.json Using a Public File <img src="/images/logo.png" alt="Application logo" /> src/app Folder The src/app folder contains the application's Angular code. src/app/ │ ├── app.component.ts ├── app.component.html ├── app.component.css ├── app.component.spec.ts ├── app.config.ts └── app.routes.ts app.component.ts The AppComponent is the root component of the application. import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; @Component({ selector: 'app-root', imports: [ RouterOutlet ], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent { title = 'My Application'; } app.component.html The root component template commonly contains the main layout and router outlet. <header> <h1> {{ title }} </h1> </header> <main> <router-outlet /> </main> app.component.css This file contains styles scoped to the root component. header { padding: 16px; border-bottom: 1px solid #ccc; } app.component.spec.ts The .spec.ts file contains unit tests for the component. import { TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; describe( 'AppComponent', () => { it( 'creates the application', async () => { await TestBed .configureTestingModule({ imports: [ AppComponent ] }) .compileComponents(); const fixture = TestBed.createComponent( AppComponent ); expect( fixture.componentInstance ).toBeTruthy(); } ); } ); app.config.ts The app.config.ts file contains application-level providers. import { ApplicationConfig } from '@angular/core'; import { provideHttpClient, withInterceptors } from '@angular/common/http'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), provideHttpClient( withInterceptors([ authInterceptor, errorInterceptor ]) ) ] }; Common app.config.ts Providers Router providers HttpClient providers HTTP interceptors Application initializers Global injection tokens Hydration configuration Application-wide services app.routes.ts The app.routes.ts file contains application routing configuration. import { Routes } from '@angular/router'; export const routes: Routes = [ { path: '', loadComponent: () => import( './features/home/pages/home-page.component' ).then( module => module.HomePageComponent ) }, { path: 'users', loadChildren: () => import( './features/users/user.routes' ).then( module => module.USER_ROUTES ) }, { path: '**', loadComponent: () => import( './shared/pages/not-found.component' ).then( module => module.NotFoundComponent ) } ]; Recommended Feature-Based Structure For medium and large applications, organize code by business feature rather than only by technical file type. src/app/ │ ├── core/ │ ├── shared/ │ ├── features/ │ ├── auth/ │ ├── users/ │ ├── products/ │ └── orders/ │ ├── layouts/ │ ├── app.component.ts ├── app.config.ts └── app.routes.ts Easy Structure Formula core = Application-Wide Infrastructure shared = Reusable UI and Utilities features = Business Functionality layouts = Page Structure app.config = Global Providers app.routes = Main Routes core Folder The core folder contains application-wide infrastructure that is normally used once across the application. core/ │ ├── authentication/ │ ├── auth.service.ts │ ├── auth.guard.ts │ └── auth.interceptor.ts │ ├── http/ │ └── error.interceptor.ts │ ├── services/ │ ├── logger.service.ts │ └── storage.service.ts │ ├── models/ │ └── api-response.model.ts │ └── tokens/ └── api-url.token.ts Core Folder Examples Authentication service Authorization guards HTTP interceptors Global error handling Storage service Application configuration Global injection tokens shared Folder The shared folder contains reusable code that can be used by multiple features. shared/ │ ├── components/ │ ├── button/ │ ├── card/ │ ├── dialog/ │ └── loader/ │ ├── directives/ │ └── autofocus.directive.ts │ ├── pipes/ │ └── initials.pipe.ts │ ├── validators/ │ └── password.validator.ts │ ├── utils/ │ └── date.util.ts │ └── models/ └── pagination.model.ts Shared Folder Rule Shared Code = Reusable + Feature Independent + Minimal Business Logic features Folder The features folder contains code grouped by business functionality. features/ │ ├── users/ │ ├── components/ │ ├── pages/ │ ├── services/ │ ├── models/ │ ├── guards/ │ ├── state/ │ └── user.routes.ts │ ├── products/ │ ├── components/ │ ├── pages/ │ ├── services/ │ ├── models/ │ └── product.routes.ts │ └── orders/ ├── components/ ├── pages/ ├── services/ ├── models/ └── order.routes.ts Complete Feature Example features/users/ │ ├── components/ │ ├── user-card/ │ │ ├── user-card.component.ts │ │ ├── user-card.component.html │ │ ├── user-card.component.css │ │ └── user-card.component.spec.ts │ │ │ └── user-form/ │ ├── user-form.component.ts │ ├── user-form.component.html │ └── user-form.component.css │ ├── pages/ │ ├── user-list-page/ │ │ └── user-list-page.component.ts │ │ │ └── user-detail-page/ │ └── user-detail-page.component.ts │ ├── services/ │ └── user.service.ts │ ├── models/ │ └── user.model.ts │ ├── state/ │ └── user.store.ts │ ├── guards/ │ └── user-access.guard.ts │ └── user.routes.ts Components vs Pages Components Pages Reusable parts of a page Connected directly to routes Receive data through inputs Load and coordinate feature data Emit user actions Connect services and child components Example: UserCardComponent Example: UserListPageComponent Feature Routes import { Routes } from '@angular/router'; export const USER_ROUTES: Routes = [ { path: '', loadComponent: () => import( './pages/user-list-page/user-list-page.component' ).then( module => module.UserListPageComponent ) }, { path: ':id', loadComponent: () => import( './pages/user-detail-page/user-detail-page.component' ).then( module => module.UserDetailPageComponent ) } ]; layouts Folder The layouts folder contains reusable application page structures. layouts/ │ ├── main-layout/ │ ├── main-layout.component.ts │ ├── header.component.ts │ └── sidebar.component.ts │ └── auth-layout/ └── auth-layout.component.ts Route Layout Example export const routes: Routes = [ { path: '', loadComponent: () => import( './layouts/main-layout/main-layout.component' ).then( module => module.MainLayoutComponent ), children: [ { path: 'users', loadChildren: () => import( './features/users/user.routes' ).then( module => module.USER_ROUTES ) } ] } ]; Models Folder Models define the structure of application data. export interface User { id: number; name: string; email: string; active: boolean; } Recommended Naming user.model.ts product.model.ts order.model.ts api-response.model.ts pagination.model.ts Services Folder Services contain reusable business logic, API calls, state operations, or shared functionality. import { HttpClient } from '@angular/common/http'; import { Injectable, inject } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UserService { private http = inject(HttpClient); getUsers() { return this.http.get<User[]>( '/api/users' ); } } State Folder The state folder contains feature state management. import { Injectable, computed, signal } from '@angular/core'; @Injectable() export class UserStore { private usersState = signal<User[]>([]); readonly users = this.usersState.asReadonly(); readonly activeUsers = computed(() => this.usersState().filter( user => user.active ) ); setUsers( users: User[] ) { this.usersState.set(users); } } Environment Configuration Environment-specific values may be stored in environment files or supplied through deployment-time configuration. src/environments/ │ ├── environment.ts ├── environment.development.ts └── environment.production.ts Example export const environment = { production: false, apiUrl: 'https://api.example.com' }; Do not store passwords, private keys, or secret credentials in frontend environment files because browser code is visible to users. Barrel Files An index.ts file can re-export related files. export { UserCardComponent } from './user-card.component'; export { UserFormComponent } from './user-form.component'; Usage import { UserCardComponent, UserFormComponent } from './components'; Use barrel files carefully. Excessive barrels can create circular dependencies and make import paths harder to understand. Single Application Structure my-app/ │ ├── public/ ├── src/ │ ├── app/ │ │ ├── core/ │ │ ├── shared/ │ │ ├── features/ │ │ ├── layouts/ │ │ ├── app.component.ts │ │ ├── app.config.ts │ │ └── app.routes.ts │ │ │ ├── index.html │ ├── main.ts │ └── styles.css │ ├── angular.json ├── package.json └── tsconfig.json Multi-Project Workspace A workspace can contain multiple applications and libraries. Create an Empty Workspace ng new company-workspace --no-create-application Generate Projects ng generate application admin-app ng generate application customer-app ng generate library shared-ui Structure company-workspace/ │ ├── projects/ │ ├── admin-app/ │ │ └── src/ │ │ │ ├── customer-app/ │ │ └── src/ │ │ │ └── shared-ui/ │ ├── src/ │ │ ├── lib/ │ │ └── public-api.ts │ │ │ └── ng-package.json │ ├── angular.json ├── package.json └── tsconfig.json Application vs Library Application Library Runs independently in a browser Provides reusable functionality Has an application entry point Has a public API Can contain routes and pages Usually exports components, services, pipes, or directives Built with ng build app-name Built with ng build library-name Library Structure projects/shared-ui/ │ ├── src/ │ ├── lib/ │ │ ├── button/ │ │ ├── card/ │ │ └── dialog/ │ │ │ └── public-api.ts │ ├── ng-package.json ├── package.json ├── tsconfig.lib.json └── tsconfig.spec.json public-api.ts The public-api.ts file defines what consumers can import from the library. export { ButtonComponent } from './lib/button/button.component'; export { CardComponent } from './lib/card/card.component'; Folder-by-File-Type Structure app/ │ ├── components/ ├── services/ ├── models/ ├── guards/ ├── directives/ └── pipes/ This structure can work for small applications, but larger projects may become difficult to maintain because files belonging to one business feature are spread across many folders. Feature-Based vs File-Type Structure Feature-Based File-Type Based Groups code by business feature Groups code by technical type Better feature isolation Simple for small projects Easier lazy loading Related code may become scattered Scales better for large applications Can become difficult to navigate Naming Conventions Type Example Component user-card.component.ts Service user.service.ts Directive autofocus.directive.ts Pipe initials.pipe.ts Guard auth.guard.ts Interceptor auth.interceptor.ts Model user.model.ts Routes user.routes.ts Test user.service.spec.ts Recommended Structure for a Medium Application src/app/ │ ├── core/ │ ├── auth/ │ ├── interceptors/ │ ├── services/ │ └── tokens/ │ ├── shared/ │ ├── components/ │ ├── directives/ │ ├── pipes/ │ ├── validators/ │ └── utils/ │ ├── features/ │ ├── dashboard/ │ ├── users/ │ ├── products/ │ └── orders/ │ ├── layouts/ │ ├── main-layout/ │ └── auth-layout/ │ ├── app.component.ts ├── app.config.ts └── app.routes.ts Common Mistakes 1. Putting Everything in app Folder Root Avoid: app/ ├── user.component.ts ├── product.component.ts ├── order.component.ts ├── user.service.ts ├── product.service.ts └── order.service.ts Group related functionality into feature folders. 2. Creating One Large Shared Folder Do not place feature-specific code in shared only because multiple files use it. 3. Putting Global Services in Every Component Application-wide services normally belong in root providers or use providedIn: 'root' . 4. Storing Secrets in Environment Files Frontend files are delivered to the browser and must not contain confidential secrets. 5. Creating Deep Folder Nesting Avoid unnecessary folder levels that make imports and navigation difficult. 6. Mixing Business Features Keep users, products, orders, and authentication in separate feature areas. 7. Using Shared as a General Dumping Folder Only place genuinely reusable and feature-independent code in shared . 8. Creating Circular Imports A feature should not import from another feature's internal files unless a deliberate shared API exists. Best Practices Organize medium and large applications by business feature Keep application-wide infrastructure in core Keep reusable UI and utilities in shared Keep route components inside feature page folders Place feature services and models near their feature Use lazy routes for large features Use clear and consistent file names Keep related component files together Avoid storing secrets in frontend files Avoid excessive folder nesting Keep public library exports in public-api.ts Allow the project structure to grow with application complexity Interview Questions What is an Angular workspace? An Angular workspace is a collection of configuration files and one or more Angular applications or libraries. What is the purpose of angular.json? It configures Angular CLI operations such as building, serving, testing, assets, styles, project targets, and output paths. What is main.ts? It is the main entry point that bootstraps the Angular application. What is app.config.ts? It contains application-level providers for standalone applications, such as routing, HttpClient, interceptors, and initializers. What is app.routes.ts? It defines the application's route configuration. What belongs in the core folder? Application-wide infrastructure such as authentication, interceptors, global services, tokens, and error handling. What belongs in the shared folder? Reusable, feature-independent components, directives, pipes, validators, models, and utilities. Why use feature-based organization? It keeps related business code together, improves maintainability, supports lazy loading, and scales better for large applications. What is the purpose of public-api.ts? It defines the public exports available to consumers of an Angular library. What is the projects folder? In a multi-project workspace, it contains additional Angular applications and libraries. Key Point A good Angular project structure keeps global infrastructure, reusable code, and business features clearly separated while keeping related files close together. Easy Formula Workspace Root = Angular and TypeScript Configuration src = Application Source app = Angular Application Code core = Global Infrastructure shared = Reusable Code features = Business Features layouts = Page Structures public = Static Files projects = Multiple Apps and Libraries