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.