Skip to content

Naming Conventions

Source: Angular 2025: New Style Guide Standards and How to Apply Them

Consistent naming conventions are fundamental to code readability and team collaboration. Angular 2025 emphasizes two key principles:

  1. Avoid Generic Names — Don’t use helpers.ts, utils.ts, common.ts
  2. Consistent Naming Across Related Files — Component files should share the same base name

From Angular 2025 style guide:

“Steer clear of generic file names like helpers.ts or utils.ts. Instead, use descriptive names that reflect the file’s purpose.”

helpers.ts — What helpers?
utils.ts — What utilities?
common.ts — Common what?
data.ts — What data?
misc.ts — Miscellaneous what?
date-formatter.ts — Clear purpose
string-validators.ts — Specific functionality
user.model.ts — Domain-specific
api-endpoints.ts — Clear category

Angular 2025 emphasizes that related files should share a common base name.

✅ Good - All related files share "user-profile" base name
user-profile.component.ts
user-profile.component.html
user-profile.component.scss
❌ Bad - Inconsistent naming
user.ts
user-view.html
user-styles.scss

Components: {name}.component.{ts|html|scss}

user-profile.component.ts
user-profile.component.html
user-profile.component.scss

Services: {name}.service.ts

user.service.ts
auth.service.ts
api.service.ts

Directives: {name}.directive.ts

highlight.directive.ts
auto-focus.directive.ts

Pipes: {name}.pipe.ts

phone-format.pipe.ts
truncate.pipe.ts

Modules (NgModule): {name}.module.ts

user.module.ts
auth.module.ts

Pattern: PascalCase, descriptive, with optional suffix for type

export class UserService {}
export class UserComponent {}
export class UserGuard {}
export class ApiInterceptor {}

Pattern: PascalCase, optional I prefix (but avoid if possible)

export interface User {
id: string;
name: string;
email: string;
}
export interface UserService {
getUser(id: string): Observable<User>;
updateUser(user: User): Observable<User>;
}

Pattern: camelCase, descriptive

// ✅ Good
private userList: User[] = [];
private isLoading = false;
private selectedUserId: string | null = null;
private maxRetries = 3;
// ❌ Bad
private users: User[] = []; // too short
private u: User[] = []; // single letter
private USER_LIST: User[] = []; // SCREAMING_SNAKE_CASE
private the_users: User[] = []; // snake_case
private x = 0; // unclear meaning

Pattern: camelCase, verb-based for actions, clear purpose

// ✅ Good - Action verbs
private loadUsers(): void {}
private fetchUserData(id: string): Observable<User> {}
private validateEmail(email: string): boolean {}
private formatPhoneNumber(phone: string): string {}
private saveChanges(): void {}
// ✅ Good - Getters
private getSelectedUser(): User | null {}
private getUserById(id: string): User {}
// ✅ Good - Checkers (is/has prefix)
private isUserAuthenticated(): boolean {}
private hasPermission(permission: string): boolean {}
// ❌ Bad
private user_data(): void {} // snake_case
private UserData(): void {} // PascalCase
private processUserDataAndSaveIt(): void {} // too long
private p(): void {} // too short
private data(): void {} // unclear what it does

Pattern: UPPER_SNAKE_CASE for true constants, camelCase for config objects

// ✅ Good - True constants
export const MAX_RETRIES = 3;
export const DEFAULT_TIMEOUT_MS = 5000;
export const API_BASE_URL = 'https://api.example.com';
// ✅ Good - Configuration objects (if immutable)
export const defaultConfig = {
timeout: 5000,
retries: 3,
debug: false
};
// ❌ Bad
export const maxRetries = 3; // should be UPPER_SNAKE_CASE
export const MAX_RETRIES_ALLOWED = 3; // redundant suffix
export const API = 'https://api.example.com'; // too short/generic
// ✅ Good - no suffix, called as functions
readonly count = signal(0);
readonly username = signal('');
readonly isLoading = signal(false);
readonly selectedUser = signal<User | null>(null);

Pattern: kebab-case with prefix

// ✅ Good
@Component({
selector: 'app-user-card', // ✅ with app- prefix
selector: 'vs-button', // ✅ with lib prefix
selector: 'lib-modal' // ✅ with lib prefix
})
// ❌ Bad
@Component({
selector: 'UserCard', // ❌ PascalCase
selector: 'user_card', // ❌ snake_case
selector: 'usercard' // ❌ no hyphen (looks like one word)
selector: 'user-card-component' // ❌ redundant suffix
})

Pattern: Feature name + .module.ts (NgModules) or feature folder for standalone

src/app/features/
├── user/ ✅ Feature folder
│ ├── user.component.ts
│ ├── user.service.ts
│ └── models/
├── admin/ ✅ Feature folder
│ ├── dashboard/
│ ├── settings/
│ └── admin.module.ts (if NgModule-based)
└── dashboard/ ✅ Feature folder
├── dashboard.component.ts
├── analytics.component.ts
└── dashboard.service.ts

Use this checklist to verify your naming is consistent:

  • All component files start with component name (e.g., user-profile.component.ts, user-profile.component.html)
  • Services end with .service.ts
  • Directives end with .directive.ts
  • Pipes end with .pipe.ts
  • No generic names (helpers.ts, utils.ts, common.ts)
  • Files use kebab-case
  • Classes and interfaces use PascalCase
  • Variables, functions, and properties use camelCase
  • Constants use UPPER_SNAKE_CASE
  • Selectors use kebab-case with a prefix
  • Feature folders are named descriptively

✅ Readability — Developer can quickly understand what each file does ✅ Searchability — Easy to find files with consistent naming ✅ Team Collaboration — Everyone follows the same conventions ✅ Maintainability — Reduces cognitive load when reading code ✅ IDE Support — Better autocomplete and refactoring tools