Roadmap › Angular (2 → 21) › Module: Getting Started
Lessons in this course (16)

4. Angular workspace folder structure explained — with sample files

Basic★ Must knowLesson 4 of 16

A real Angular 17+ application (standalone components, no NgModules) organised by core / shared / features:

text
shop-ui/
├── angular.json                     workspace config: build/serve/test targets, assets, styles, budgets
├── package.json · tsconfig.json · tsconfig.app.json
├── proxy.conf.json                  dev-server proxy: /api → https://localhost:7001 (avoids CORS in dev)
├── public/                          static assets copied to the build (favicon, images)
└── src/
    ├── index.html                   <app-root></app-root>
    ├── main.ts                      bootstrapApplication(App, appConfig)
    ├── styles.scss                  global styles
    ├── environments/
    │   ├── environment.ts           { production: false, apiUrl: '/api' }
    │   └── environment.prod.ts      { production: true, apiUrl: 'https://api.shop.com/api' }
    └── app/
        ├── app.ts / app.html / app.scss    root component (shell: header, <router-outlet>)
        ├── app.config.ts            providers: router, HttpClient + interceptors, animations
        ├── app.routes.ts            top-level routes with lazy-loaded features
        ├── core/                    singletons used once app-wide
        │   ├── interceptors/auth.interceptor.ts, error.interceptor.ts
        │   ├── guards/auth.guard.ts
        │   ├── services/auth.service.ts
        │   └── layout/header/header.ts
        ├── shared/                  reusable dumb components, pipes, directives
        │   ├── components/spinner/spinner.ts
        │   └── pipes/inr-currency.pipe.ts
        └── features/
            ├── products/
            │   ├── products.routes.ts            feature routes (lazy)
            │   ├── data/product.service.ts       HTTP calls
            │   ├── data/product.model.ts         interfaces
            │   ├── product-list/product-list.ts  + .html + .scss + .spec.ts
            │   └── product-detail/product-detail.ts
            └── orders/ …
ts
// src/app/app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideZonelessChangeDetection(),                // Angular 20+ (zoneless)
    provideRouter(routes, withComponentInputBinding()),
    provideHttpClient(withInterceptors([authInterceptor, errorInterceptor])),
  ],
};

// src/app/app.routes.ts
export const routes: Routes = [
  { path: '', redirectTo: 'products', pathMatch: 'full' },
  { path: 'products', loadChildren: () => import('./features/products/products.routes').then((m) => m.PRODUCT_ROUTES) },
  { path: 'orders', canActivate: [authGuard], loadChildren: () => import('./features/orders/orders.routes').then((m) => m.ORDER_ROUTES) },
  { path: '**', loadComponent: () => import('./shared/components/not-found/not-found').then((m) => m.NotFound) },
];

// src/app/features/products/products.routes.ts
export const PRODUCT_ROUTES: Routes = [
  { path: '', component: ProductList },
  { path: ':id', component: ProductDetail },          // :id bound to an input() via withComponentInputBinding
];

Rules of thumb: core = provided once (interceptors, guards, auth), shared = imported by many features (no business logic), features = lazy-loaded business areas; one component per folder with its template, styles and spec.