home/docs/database-naming-conventions

Database Naming Conventions

Consistent naming for tables, columns, keys, and relationships.

Consistent naming makes relationships discoverable, data types obvious, and audits straightforward. If a column ends in _id, you immediately know it's a relationship to another table and likely needs an index.

Casing

All database constructs (tables, columns, nodes, predicates) use lowercase with underscores separating words.

customer_addresses
user_id
first_name

Singular vs. Plural

Tables hold many rows, so they use plural names. Columns represent a single value per row, so they're always singular.

CREATE TABLE customers (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  first_name  VARCHAR(255),
  last_name   VARCHAR(255),
  is_active   BOOLEAN DEFAULT TRUE,
  inserted_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at  TIMESTAMPTZ DEFAULT NOW()
);

Primary and Foreign Keys

The primary key is always id. A foreign key uses the singular form of the related table followed by _id.

If users has a one-to-many relationship with addresses, the foreign key column is user_id:

CREATE TABLE addresses (
  id      UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL,
  street  VARCHAR(255),
  city    VARCHAR(255)
);

Using id with UUIDs or ULIDs

id is not limited to integers. If your project uses UUIDs or ULIDs as primary keys, id and _id still work as long as you're consistent across the dataset. The column name describes the role (primary key, foreign key), not the data type.

CREATE TABLE orders (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  customer_id UUID NOT NULL,
  total       INTEGER NOT NULL
);

When to use _uid

If you're mixing integer-based IDs and universal IDs within the same dataset, use _uid for universal foreign keys to remove ambiguity. The suffix is _uid rather than _uuid because the value isn't always a UUID type. It could be a UUID, ULID, or any other universally unique value.

When universal IDs are the only ID type in your schema, stick with _id. No suffix gymnastics needed.

-- Mixed: integer PKs on some tables, UUIDs on others
ALTER TABLE comments ADD COLUMN post_uid UUID NOT NULL;
ALTER TABLE comments ADD COLUMN author_id BIGINT NOT NULL;

External IDs

Use _xid for identifiers that come from external systems. These are typically strings and don't need to follow your internal conventions since the format is dictated by the vendor.

ALTER TABLE locations ADD COLUMN google_place_xid VARCHAR(255);
ALTER TABLE payments  ADD COLUMN stripe_charge_xid VARCHAR(255);

Notes

  • UUID and GUID are the same thing. GUID is more common in the Microsoft ecosystem.
  • Foreign keys may or may not have database-level constraints. In data warehouses, tables are often joined without formal foreign key constraints.

Column Suffixes

Suffix Meaning Example
_id Foreign key (integer, or UUID/ULID when used consistently) user_id
_uid Universal foreign key when mixing ID types address_uid
_xid External/vendor ID google_place_xid
_at Datetime/timestamp created_at
_on Date (no time component) published_on

Column Prefixes

Prefix Meaning Example
is_ Boolean state is_active
has_ Boolean possession has_logged_in
can_ Boolean capability can_export
do_ Boolean action flag do_notify