A well-organised Angular project structure makes the codebase navigable for teams, ensures features can be developed and tested independently, and keeps shared code discoverable. The feature-based structure — where all files related to a feature (component, service, model, test) live together under features/{feature-name}/ — is the Angular team’s recommendation for medium-to-large applications. The alternative (type-based structure: all components in one folder, all services in another) becomes unwieldy as the application grows beyond a few features.
Recommended Project Structure
// ── Feature-based structure for the BlogApp ───────────────────────────────
// src/app/
// ├── core/ ← singleton services (once per app)
// │ ├── interceptors/
// │ │ ├── auth.interceptor.ts ← adds JWT to requests
// │ │ └── error.interceptor.ts ← handles 401, 500 globally
// │ ├── guards/
// │ │ ├── auth.guard.ts ← requires authentication
// │ │ └── admin.guard.ts ← requires Admin role
// │ └── services/
// │ └── auth.service.ts ← login, logout, token state
// │
// ├── features/ ← feature-specific code
// │ ├── posts/
// │ │ ├── post-list.component.ts ← /posts route
// │ │ ├── post-detail.component.ts ← /posts/:slug route
// │ │ ├── post-create.component.ts ← /posts/new route
// │ │ └── posts.service.ts ← HTTP calls for posts
// │ ├── auth/
// │ │ ├── login.component.ts
// │ │ ├── register.component.ts
// │ │ └── auth.service.ts ← login/register HTTP calls
// │ └── admin/
// │ ├── admin-dashboard.component.ts
// │ └── admin.service.ts
// │
// ├── shared/ ← reusable across features
// │ ├── components/
// │ │ ├── loading-spinner.component.ts
// │ │ └── error-message.component.ts
// │ ├── pipes/
// │ │ └── time-ago.pipe.ts
// │ └── directives/
// │ └── click-outside.directive.ts
// │
// └── models/ ← TypeScript interfaces matching API DTOs
// ├── post.ts ← PostDto, PostSummaryDto, CreatePostRequest
// ├── auth.ts ← AuthResponse, LoginRequest, RegisterRequest
// └── pagination.ts ← PagedResult
// ── Model interfaces — mirror ASP.NET Core DTOs ───────────────────────────
// src/app/models/post.ts
export interface PostSummaryDto {
id: number;
title: string;
slug: string;
authorName: string;
publishedAt: string;
viewCount: number;
commentCount: number;
tags: string[];
}
export interface PagedResult<T> {
items: T[];
page: number;
pageSize: number;
total: number;
totalPages: number;
hasNextPage: boolean;
hasPrevPage: boolean;
}
core/ folder contains services and providers that should be instantiated once for the entire application — authentication, HTTP interceptors, and app-wide error handling. Services in core/ are typically provided at the root level with providedIn: 'root'. The shared/ folder contains components, pipes, and directives that are reused across multiple features but are not singletons. The features/ folder contains everything related to a specific domain — components, services, models, and guards that belong to that feature.tsconfig.json to avoid fragile relative imports. With "@models/*": ["src/app/models/*"], every component imports models as import { PostDto } from '@models/post' instead of import { PostDto } from '../../../models/post'. Relative paths break when components are moved; path aliases always resolve from the project root. Add the same paths to angular.json under compilerOptions for the build to resolve them correctly.shared/ and import from there. If the shared code is complex enough, consider creating a separate feature folder for it (e.g., features/notifications/ instead of having both posts/ and auth/ import notification components directly).Common Mistakes
Mistake 1 — Type-based structure for large apps (all components in one folder)
❌ Wrong — components/ folder with 30 unrelated components; hard to find feature-related code.
✅ Correct — feature-based structure: all post-related code in features/posts/.
Mistake 2 — Importing models from other feature folders (cross-feature coupling)
❌ Wrong — auth/login.component.ts imports PostDto from features/posts/models/.
✅ Correct — shared interfaces in models/ at app level; feature-specific models stay in the feature folder.