Skip to content

Naming Conventions

Consistent naming is one of the highest-leverage investments a team can make. When every engineer follows the same conventions, any file in the codebase becomes immediately readable — even to someone who has never touched that module before.

This document is the single source of truth for naming across all NestJS services and PostgreSQL schemas in this monorepo. When in doubt, refer here first.

  • Pattern: Singular + Module
  • Rationale: A module is a single, cohesive organizational unit — it encapsulates a domain concept, not a collection.
  • Examples: OrderModule, UserModule, AppointmentModule
  • Pattern: Plural + Controller
  • Rationale: A controller typically manages multiple endpoints for a resource (GET /orders, GET /orders/:id, POST /orders).
  • Examples: OrdersController, UsersController, AppointmentsController
  • Pattern: Plural + Service (or action-based for complex operations)
  • Rationale: A service provides multiple methods for operating on a resource. For complex workflows, an action-based name is clearer.
  • Examples: OrdersService, UsersService, AppointmentCheckInService
  • Class name: Singular, PascalCase
    • Order (Entity), CreateOrderDTO (DTO), UpdateOrderDTO (DTO)
  • Properties: snake_case
  • Rationale: Entity properties map 1-to-1 with PostgreSQL column names (which are conventionally snake_case). This eliminates the need for @Column({ name: '...' }) on every field.
// ✅ Correct entity property naming
export class Order {
created_at: Date;
total_amount: number;
is_fulfilled: boolean;
customer_id: string;
}
  • Pattern: Singular, PascalCase
  • Rationale: An enum represents a single set of related constants.
  • Examples: OrderStatus, UserRole, PaymentMethod
  • Pattern: kebab-case + .{type}.ts
  • Rationale: Kebab-case is unambiguous across case-sensitive and case-insensitive filesystems. The type suffix makes the file’s role immediately clear.
TypeConventionExample
ModuleSingularorder.module.ts
ControllerPluralorders.controller.ts
ServicePluralorders.service.ts
EntitySingularorder.entity.ts
DTOSingular resourcecreate-order.dto.ts
Events ControllerSingular + -eventsorder-events.controller.ts
  • Pattern: Singular + kebab-case
  • Rationale: The folder represents the domain concept (singular), matching the Module name.
  • Examples: modules/order/, modules/appointment/, modules/notification/

Use path aliases instead of relative imports when referencing code across module boundaries:

// ✅ Correct: alias-based import
import { CreateOrderDTO } from '@apps/orders-bc/src/modules/order/dto/create-order.dto';
// ❌ Wrong: fragile relative import
import { CreateOrderDTO } from '../../dto/create-order.dto';
  • Pattern: camelCase (standard TypeScript convention)
  • Examples: const orderTotal, function calculateDiscount(), const isExpired

This is one of the most impactful naming conventions in the codebase. Without prefixes, boolean fields are ambiguous. With them, the field name reads like a question with an obvious yes/no answer.

Without PrefixWith PrefixWhy the Prefix Wins
activeis_activeactive could be a noun, an adjective, or a verb. is_active unambiguously asks: “Is this currently active?”
loadedis_loadedPast participle or current state? is_loaded is always a state check.
permissionhas_permissionDoes the field contain permission data, or indicate that permission exists?
editcan_editIs this a command or a capability flag? can_edit is always a capability.
refreshshould_refreshA stored flag that drives conditional behavior — should_ makes that intent clear.
PrefixMeaningExamples
is_Current state or identityis_active, is_deleted, is_verified, is_archived
has_Possession or existence of somethinghas_error, has_permission, has_attachment, has_signature
can_Ability or authorizationcan_edit, can_delete, can_approve, can_upload
should_Conditional action or system behaviorshould_notify, should_refresh, should_archive, should_validate
// ❌ Ambiguous — what does each field mean?
approved: boolean;
email_verified: boolean;
admin: boolean;
public: boolean;
// ✅ Self-documenting — each field answers its own question
is_approved: boolean; // Is this record currently approved?
is_email_verified: boolean; // Has the user's email been confirmed?
is_admin: boolean; // Does this user have admin privileges?
is_public: boolean; // Is this resource accessible without auth?
has_attachments: boolean; // Are there associated file attachments?
has_errors: boolean; // Did validation produce errors?
can_edit: boolean; // Is the current user allowed to edit?
can_delete: boolean; // Is the current user allowed to delete?
should_notify: boolean; // Should a notification be sent on save?
should_archive: boolean; // Should this record be archived on completion?

  • Pattern: plural, snake_case
  • Rationale: A table holds a collection of records, so the plural form is natural.
  • Examples: orders, users, appointment_slots, payment_transactions
  • Pattern: snake_case
  • Examples: first_name, created_at, is_active, total_amount
  • Pattern: id (column name), pk_<table_name> (constraint name)
  • Example: Column id with constraint pk_orders
  • Pattern: singular_table_name_id (column), fk_<table>_<referenced_table> (constraint)
  • Example: customer_id in the orders table referencing customers
  • Pattern: idx_<table_name>_<column_names>
  • Examples: idx_orders_customer_id, idx_users_email, idx_appointments_scheduled_at
  • Pattern: uq_<table_name>_<column_names>
  • Examples: uq_users_email, uq_orders_reference_number
  • Pattern: chk_<table_name>_<condition>
  • Examples: chk_orders_status, chk_appointments_type

CategoryPattern / FormatRationaleExamples
ModulesSingular + ModuleA module is a single cohesive unitOrderModule, UserModule
ControllersPlural + ControllerHandles multiple endpoints per resourceOrdersController, UsersController
ServicesPlural + ServiceProvides multiple methods per resourceOrdersService, UsersService
Entity ClassSingular, PascalCaseOOP & NestJS conventionOrder, User
Entity Propertiessnake_caseDirect 1-to-1 map to PostgreSQL columnscreated_at, is_active
DTOsSingular, PascalCaseRepresents a single data transfer shapeCreateOrderDTO, UpdateUserDTO
EnumsSingular, PascalCaseRepresents a single set of constantsOrderStatus, UserRole
FoldersSingular + kebab-caseMatches the domain concept nameorder/, appointment/
Filenameskebab-case + .type.tsClear type-to-file mappingorder.entity.ts, orders.service.ts
Table Namesplural, snake_casePlural = collection of recordsorders, payment_transactions
Column Namessnake_casePostgreSQL standard conventionfirst_name, created_at
Primary Keysid / pk_<table>Consistent PK namingpk_orders
Foreign Keys<ref_table_singular>_idClearly references parent tablecustomer_id
Indexesidx_<table>_<columns>Searchable, meaningful index namesidx_orders_customer_id
Unique Constraintsuq_<table>_<columns>Explicit uniqueness enforcementuq_users_email
Check Constraintschk_<table>_<condition>DB-level validation namingchk_orders_status