Skip to main content

Database Naming

Tables and Columns

Use snake_case throughout. Be explicit — avoid abbreviations.

-- Good:
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
email_address VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
is_email_verified BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE TABLE user_roles (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
role_name VARCHAR(50) NOT NULL,
granted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
granted_by BIGINT REFERENCES users(id)
);

-- Avoid — PascalCase, abbreviations, generic names:
CREATE TABLE User (
id BIGSERIAL PRIMARY KEY,
fname VARCHAR(100),
lname VARCHAR(100),
email VARCHAR(255),
pwd_hash VARCHAR(255),
verified BOOLEAN,
created TIMESTAMP WITH TIME ZONE,
modified TIMESTAMP WITH TIME ZONE
);

Index Naming

Follow a {type}_{table}_{column(s)} pattern:

PrefixType
idx_Standard index
uniq_Unique index
pk_Primary key (often implicit)
fk_Foreign key constraint
-- Good:
CREATE INDEX idx_users_email_address ON users(email_address);
CREATE INDEX idx_users_created_at ON users(created_at);
CREATE UNIQUE INDEX uniq_user_roles_user_role ON user_roles(user_id, role_name);

-- Avoid:
CREATE INDEX idx1 ON users(email_address);
CREATE INDEX user_idx ON users(created_at);

Conventions at a Glance

ObjectConventionExample
TablesPlural nounsusers, orders, user_roles
ColumnsSingular nouns/adjectivesemail_address, created_at
Booleansis_ or has_ prefixis_active, has_attachment
Timestamps_at suffixcreated_at, deleted_at
Foreign keysReferenced table + _iduser_id, order_id
Junction tablesBoth table names combineduser_roles, order_items