Skip to content

Database naming conventions#

Naming conventions to help every contributor speak the same schema.

Info

Some of the naming conventions here are new, and some are revised from old/existing conventions. Existing code and existing database objects are not expected to follow these conventions perfectly. New code and new database objects should follow these conventions.

Databases#

  • The name of a database is a hybrid of Pascal case and snake case. Partition_Environment_Application
  • Examples:
    • E00_Development_Engine
    • E02_Sandbox_Shift
    • E05_Production_Shift

Schemas#

  • The name of a schema is lowercase and singular form.
  • A schema name should match a component (toolkit) name.
  • Examples:
    • billing
    • platform

Tables#

  • T = The name of a base Table (i.e., a non-projection table) has a T prefix. A base table stores raw, unprojected data.
  • P = The name of a Projection table (also called a Query table) has an R prefix (or a Q prefix). A projection table stores a projection of data from a base table.
  • B = The name of a temporary Buffer table has a B prefix. A buffer table caches intermediate results for complex multi-stage algorithms, queries, and reports.
  • Z = The name of deprecated Zombie table has a Z prefix. A zombie table is a candidate for removal or replacement.
  • The name of a table name is singular Pascal case (i.e. the first letter of each word in a compound word is capitalized).
  • Examples:
    • Good: TUser, BComplexReportPreparation
    • Bad: User, Users, TUsers

Views#

  • The name of a view has a V prefix.
  • The name of an indexed view has an X prefix.
  • The name of a view is singular Pascal case.
  • Examples:
    • VOrganizationDetail
    • XFastInventorySummary

Warning

This is a question for future discussion: should the name of a view follow the naming convention for a query?

Stored procedures#

  • The name of a stored procedure follows the naming convention for queries and commands.
  • If it is not possible to follow the naming convention for queries and commands, then the name of a stored procedure has a P prefix.

Columns#

  • The name of a column is Pascal case.
  • Ideally, a column name should be unique.
    • If two different tables contain a column with the same name, then both columns should have the same meaning.
    • If two different columns have different meanings then they should have different names.
    • For example, TUser.FullName and TPerson.FullName may be acceptable, but TUser.Name and TModule.Name is not recommended because a person's full name is not semantically equivalent to a module's name. Therefore, TUser.FullName and TModule.ModuleName are better column names.
  • The name of a column that stores an email notification message identifier should follow this convention:
    • When \<ChangeType> Notify \<RecipientDescriptor> MessageIdentifier
    • For example: WhenCrazyWidgetColorChangedNotifyMyImaginaryFriendsInGreenlandMessageIdentifier
    • Notice the terms When, Notify, and MessageIdentifier can be used (if needed) to parse the ChangeType and/or RecipientDescriptor from this type of a column name.

Data types#

  • If a date/time column contains both a Date part and a Time part then the data type must be DATETIMEOFFSET to ensure the meaning of its values is unambiguous with regard to time zone.
  • If a date/time column contains a Date part only then the data type must be DATE.
  • If a date/time column contains a Time part only then the data type must be TIME.

Entity Framework#

  • The name of an entity class should match the name of the database table (or view) to which it binds, with the suffix "Entity".
    • For example, if an entity class binds to a database table named TRole, then the C# entity class should be named TRoleEntity.
  • The name of an entity type configuration class should match the name of the database table (or view) to which it binds, with the suffix "Configuration".
    • For example, TRoleConfiguration.
  • The name of a DbSet<T> property within a DbContext class should exactly match the name of the database table (or view) to which it binds.
    • For example, if a DbContext contains a property of type DbSet<TOrganizationEntity>, which binds to the database table named QOrganization, then the name of the property should be QOrganization: internal DbSet<OrganizationEntity> QOrganization { get; set; }

SQL Server versus PostgreSQL#

The naming conventions above are intended for SQL Server databases, and are not a good fit for PostgreSQL databases because PostgreSQL automatically applies lowercase to object names.

Therefore, upper case letters are strongly discouraged. For details, refer to this article: Do not use upper case table or column names in PostgreSQL.

Snake case is strongly recommended for all object names in PostgreSQL databases.

When you use PostgreSQL, follow the de-facto standards.

Timestamps (date + time):

  • created_at and updated_at — by far the most popular, especially in web applications and ORMs
  • created_on and updated_on — alternative that some prefer
  • created_when and updated_when — grammatically logical but rarely used in open-source projects

Date-only columns:

  • created_date, start_date, end_date
  • birth_date, due_date, etc.

Time-only columns:

  • created_time, start_time, end_time

User identity columns:

  • created_by and updated_by — storing the user ID (foreign key)
  • created_by_id and updated_by_id — more explicit about storing an ID
  • creator_id and updater_id — noun-based approach
  • created_by_user_id and updated_by_user_id — very explicit but verbose

The pattern created_by and updated_by is overwhelmingly the most popular in open-source projects, with the assumed understanding that "by" is an alias for "id".

updated_at is significantly more popular than modified_at, though both are grammatically correct. This is mainly a semantic preference, because developers tend to think of database operations as:

  • CREATEcreated_at
  • UPDATEupdated_at
  • DELETEdeleted_at (for soft deletes)

This maps directly to CRUD operations, making updated_at feel more natural in a database context.