Skip to content

Naming Convention Best Practices - Industry Research

Date: 2026-01-05 Status: Research & Recommendation Sources: dbt Labs, Snowflake, GitLab dbt project, Fishtown Analytics, Kimball methodology


Key Principle: Prefixes Should Add Information, Not Repeat It

❌ Redundant (BAD):

SILVER.SILVER_CONTACT_EXPORT    -- "SILVER" is already in schema name
SILVER.WH_CONTACT_EXPORT        -- "WH" (warehouse) is just another word for SILVER
GOLD.DM_SCORECARD               -- "DM" (data mart) is just another word for GOLD

✅ Semantic (GOOD):

GOLD.REPORT_AGENT_KPIS          -- "REPORT" indicates it's aggregated for reporting
GOLD.ENRICHED_CONTACTS          -- "ENRICHED" indicates it has joins/enrichment
GOLD.BASE_CONTACTS              -- "BASE" indicates it's the foundational table

Principle: Prefix adds semantic meaning about what type of model it is, not where it lives.


Industry Best Practices Research

1. dbt Labs Official Recommendations

Source: dbt Style Guide

Their recommended prefixes:

Prefix Layer Meaning
stg_ Staging One-to-one with source tables, light transformations
int_ Intermediate Reusable logic, not exposed to end users
fct_ Marts Fact tables (events, transactions)
dim_ Marts Dimension tables (entities, reference data)

Key insight from dbt Labs:

"Use prefixes to indicate the type of model, not the layer. The folder structure indicates the layer."

Example from dbt Labs:

models/
├── staging/
│   ├── stg_customers.sql        -- Prefix indicates staging model
│   └── stg_orders.sql
├── intermediate/
│   ├── int_orders_pivoted.sql   -- Prefix indicates intermediate
│   └── int_customer_orders.sql
└── marts/
    ├── fct_orders.sql           -- Prefix indicates fact table
    ├── dim_customers.sql        -- Prefix indicates dimension
    └── dim_products.sql

Translation to our architecture: - Staging → Our SILVER layer - Intermediate → We skip this (no intermediate layer) - Marts → Our GOLD layer


2. GitLab's dbt Project (Large Production Example)

Source: GitLab Analytics dbt project

Their naming convention:

models/
├── legacy/
│   └── staging/
│       ├── sfdc/
│       │   ├── stg_sfdc_account.sql
│       │   └── stg_sfdc_opportunity.sql
├── common/
│   ├── facts/
│   │   ├── fct_event.sql
│   │   ├── fct_usage_ping.sql
│   │   └── fct_mrr.sql
│   ├── dimensions/
│   │   ├── dim_date.sql
│   │   ├── dim_user.sql
│   │   └── dim_namespace.sql
│   └── aggregates/
│       ├── agg_usage_metrics_monthly.sql
│       └── agg_revenue_daily.sql

Key patterns: - stg_ for staging models - fct_ for fact tables (granular events) - dim_ for dimension tables (entities) - agg_ for aggregated tables (rolled up metrics)

Insight: They use semantic prefixes to indicate grain and purpose, not layer.


3. Snowflake Best Practices

Source: Snowflake documentation & field guides

Snowflake recommendations: - Use descriptive names that indicate purpose - Avoid cryptic abbreviations - Use consistent patterns - Schema provides layer context, table name provides entity/purpose

Example from Snowflake customers:

-- Layer indicated by schema
ANALYTICS.FCT_SALES            -- Fact table
ANALYTICS.DIM_CUSTOMER         -- Dimension table
ANALYTICS.AGG_REVENUE_DAILY    -- Aggregate table
ANALYTICS.RPT_EXECUTIVE_DASHBOARD  -- Report/view

Pattern: {TYPE}_{ENTITY}_{GRAIN} (optional grain)


4. Fishtown Analytics (dbt Creators)

Source: dbt Discourse forums

Their philosophy:

"Prefixes should answer: What kind of model is this? Not: Where does it live?"

Recommended prefixes for marts:

Type Prefix Example Purpose
Fact tables fct_ fct_orders, fct_events Immutable events/transactions
Dimension tables dim_ dim_customers, dim_products Entities/reference data
Aggregates agg_ or rpt_ agg_sales_daily, rpt_revenue Pre-aggregated metrics

Key quote:

"Think about what your end users need to understand. 'fct_orders' tells them it's granular order data. 'orders' could be anything."


5. Kimball Methodology (Traditional Data Warehousing)

Source: "The Data Warehouse Toolkit" by Ralph Kimball

Classic Kimball prefixes: - FACT_ - Fact tables (measurements, metrics) - DIM_ - Dimension tables (descriptive attributes) - AGG_ - Aggregate tables (pre-summarized) - BRG_ - Bridge tables (many-to-many relationships)

Still relevant today: The semantic meaning behind fact vs dimension is useful.


Principle: Use semantic prefixes that indicate model TYPE, not layer


BRONZE Layer

Schema: {CLIENT}_DB.BRONZE

Naming: {SOURCE}_{OBJECT}

No prefix needed - source name already provides context

Examples:

WBP_DB.BRONZE.GLADLY_CONTACT_TIMESTAMPS
WBP_DB.BRONZE.GLADLY_CONVERSATION_TIMESTAMPS
WBP_DB.BRONZE.SPROUT_MESSAGES
WBP_DB.BRONZE.GSPREAD_ROSTER_RAW

Rationale: Source system name (GLADLY, SPROUT, GSPREAD) serves as the prefix.


SILVER Layer

Schema: {CLIENT}_DB.SILVER

Naming: {OBJECT} (no prefix) OR base_{OBJECT}

Examples:

-- Option A: No prefix (my current recommendation)
WBP_DB.SILVER.CONTACT_TIMESTAMPS
WBP_DB.SILVER.CONVERSATION_TIMESTAMPS
WBP_DB.SILVER.INBOX_GLOSSARY

-- Option B: With base_ prefix (dbt-style)
WBP_DB.SILVER.BASE_CONTACT_TIMESTAMPS
WBP_DB.SILVER.BASE_CONVERSATION_TIMESTAMPS
WBP_DB.SILVER.BASE_INBOX_GLOSSARY

Rationale: - Silver is 1:1 with Bronze (same grain, just typed/cleaned) - Schema name already indicates layer - base_ prefix (if used) indicates "baseline historical table"

Recommendation: No prefix - keep it simple. Silver tables are foundational by definition.


GOLD Layer (THREE TYPES - Need Differentiation)

Schema: {CLIENT}_DB.GOLD

Challenge: Gold has three types of models that need clear differentiation.


Type 1: Fact Tables (Enriched grain-level data)

Naming: fct_{OBJECT} or {OBJECT} (plural)

Purpose: Granular fact tables with enrichment (same grain as Silver but with JOINs)

Examples:

-- With prefix (dbt-style)
GOLD.FCT_CONTACTS               -- Contact-level facts
GOLD.FCT_CONVERSATIONS          -- Conversation-level facts
GOLD.FCT_MESSAGES               -- Message-level facts

-- Without prefix (simpler)
GOLD.CONTACTS                   -- Contact facts
GOLD.CONVERSATIONS              -- Conversation facts
GOLD.MESSAGES                   -- Message facts

Characteristics: - Same grain as Silver (row per contact/conversation) - Enriched with employee metadata + glossaries - Filtered to relevant records (XO agents only) - This is the SOT for ad-hoc analysis


Type 2: Dimension Tables (Current state entities)

Naming: dim_{ENTITY} (singular)

Purpose: Current state of entities (SCD Type 1 or latest snapshot)

Examples:

GOLD.DIM_AGENT                  -- Current agent roster
GOLD.DIM_INBOX                  -- Current inbox configuration
GOLD.DIM_QUEUE                  -- Current queue definitions

Characteristics: - Slowly changing dimensions - Usually Type 1 (latest state) or Type 2 (historical) - Reference data for joining with facts


Type 3: Aggregate Tables (Metrics/KPIs)

Naming: agg_{SUBJECT}_{GRAIN} or rpt_{SUBJECT}_{GRAIN}

Purpose: Pre-aggregated metrics for reporting/dashboards

Examples:

GOLD.AGG_AGENT_DAILY            -- Agent metrics by day
GOLD.AGG_AGENT_HOURLY           -- Agent metrics by hour
GOLD.AGG_CHANNEL_DAILY          -- Channel metrics by day
GOLD.AGG_QUEUE_DAILY            -- Queue performance by day

-- OR with "report" prefix
GOLD.RPT_AGENT_DAILY            -- Agent daily report
GOLD.RPT_EXECUTIVE_WEEKLY       -- Executive weekly report

Characteristics: - Aggregated from fact tables - Pre-calculated for performance - Standard KPI schema + client-specific columns


Type 4: Views (Consumption layer)

Naming: v_{PURPOSE} or just {PURPOSE} with VIEW materialization

Purpose: Tableau/analyst consumption views

Examples:

-- With v_ prefix (traditional)
GOLD.V_AGENT_DASHBOARD          -- Tableau dashboard
GOLD.V_AGENT_AD_HOC             -- Ad-hoc analysis
GOLD.V_EXECUTIVE_SUMMARY        -- Executive view

-- Without prefix (rely on materialization type)
GOLD.AGENT_DASHBOARD            -- VIEW (shown in Snowflake metadata)
GOLD.AGENT_AD_HOC               -- VIEW
GOLD.EXECUTIVE_SUMMARY          -- VIEW

Characteristics: - Always VIEW materialization (no storage) - JOINs with targets, variance calculations - Tableau-optimized


✅ Final Recommendation: Use Semantic Prefixes in Gold

Type Prefix Example Materialization
Bronze {SOURCE}_ GLADLY_CONTACTS table
Silver None CONTACT_TIMESTAMPS table/incremental
Gold Facts fct_ fct_contacts table/incremental
Gold Dims dim_ dim_agent table/incremental
Gold Aggs agg_ or rpt_ agg_agent_daily table
Gold Views v_ or none v_agent_dashboard view

Applied to Your Use Case

-- BRONZE (source prefix built-in)
WBP_DB.BRONZE.GLADLY_CONTACT_TIMESTAMPS
WBP_DB.BRONZE.GLADLY_CONVERSATION_TIMESTAMPS
WBP_DB.BRONZE.GSPREAD_INBOX_GLOSSARY_RAW

-- SILVER (no prefix - foundational tables)
WBP_DB.SILVER.CONTACT_TIMESTAMPS
WBP_DB.SILVER.CONVERSATION_TIMESTAMPS
WBP_DB.SILVER.INBOX_GLOSSARY
WBP_DB.SILVER.QUEUE_GLOSSARY

-- GOLD FACTS (fct_ prefix - grain-level enriched data)
WBP_DB.GOLD.FCT_CONTACTS              -- Enriched contacts (SOT for analysts)
WBP_DB.GOLD.FCT_CONVERSATIONS         -- Enriched conversations
WBP_DB.GOLD.FCT_MESSAGES              -- Enriched messages

-- GOLD DIMENSIONS (dim_ prefix - current state entities)
WBP_DB.GOLD.DIM_AGENT                 -- Current agent roster
WBP_DB.GOLD.DIM_INBOX                 -- Current inbox config
WBP_DB.GOLD.DIM_QUEUE                 -- Current queue definitions

-- GOLD AGGREGATES (agg_ prefix - pre-aggregated metrics)
WBP_DB.GOLD.AGG_AGENT_DAILY           -- Agent KPIs by day
WBP_DB.GOLD.AGG_AGENT_HOURLY          -- Agent KPIs by hour
WBP_DB.GOLD.AGG_CHANNEL_DAILY         -- Channel metrics by day
WBP_DB.GOLD.AGG_EXECUTIVE_WEEKLY      -- Executive summary by week

-- GOLD VIEWS (v_ prefix - consumption layer)
WBP_DB.GOLD.V_AGENT_DASHBOARD         -- Tableau agent view
WBP_DB.GOLD.V_AGENT_AD_HOC            -- Ad-hoc analysis view
WBP_DB.GOLD.V_EXECUTIVE_SUMMARY       -- Executive view

Why This Convention Works

Benefit 1: Self-Documenting

-- What is this table?
SELECT * FROM WBP_DB.GOLD.FCT_CONTACTS;
-- "fct_" → It's a fact table (granular, enriched)

SELECT * FROM WBP_DB.GOLD.AGG_AGENT_DAILY;
-- "agg_" → It's aggregated metrics

SELECT * FROM WBP_DB.GOLD.DIM_AGENT;
-- "dim_" → It's a dimension table (current state)

User immediately knows grain and purpose.


Benefit 2: Consistent with Industry Standards

  • dbt Labs uses fct_, dim_, agg_
  • GitLab uses fct_, dim_, agg_
  • Kimball uses FACT_, DIM_, AGG_

New team members already understand the pattern.


Benefit 3: Easy Filtering in Tools

-- Show all fact tables
SHOW TABLES IN WBP_DB.GOLD LIKE 'FCT_%';

-- Show all aggregates
SHOW TABLES IN WBP_DB.GOLD LIKE 'AGG_%';

-- Show all views
SHOW VIEWS IN WBP_DB.GOLD;

Tooling and queries can filter by prefix.


Benefit 4: Tableau Data Source Organization

Tableau Data Sources:
├── 📊 Facts
│   ├── FCT_CONTACTS
│   ├── FCT_CONVERSATIONS
│   └── FCT_MESSAGES
├── 📐 Dimensions
│   ├── DIM_AGENT
│   ├── DIM_INBOX
│   └── DIM_QUEUE
└── 📈 Reports
    ├── AGG_AGENT_DAILY
    └── V_AGENT_DASHBOARD

Tableau users can easily find what they need.


Benefit 5: Clear Lineage in dbt Docs

dbt automatically generates docs showing: - Table type (based on prefix) - Grain (rows per contact vs rows per agent-day) - Upstream dependencies


Alternative: Shorter Prefixes (Modern Style)

Some teams prefer shorter prefixes for readability:

Type Traditional Modern Short Example
Fact fct_ f_ f_contacts
Dimension dim_ d_ d_agent
Aggregate agg_ a_ or m_ (metrics) a_agent_daily, m_agent_daily
View v_ v_ v_dashboard

Example with short prefixes:

GOLD.F_CONTACTS              -- Fact
GOLD.D_AGENT                 -- Dimension
GOLD.M_AGENT_DAILY           -- Metrics (aggregate)
GOLD.V_AGENT_DASHBOARD       -- View

Trade-off: Shorter is cleaner, but less immediately obvious to new users.


Use full prefixes for clarity (you have diverse clients, make it obvious):

-- BRONZE: Source name is the prefix
BRONZE.GLADLY_CONTACT_TIMESTAMPS
BRONZE.SPROUT_MESSAGES

-- SILVER: No prefix (foundational tables)
SILVER.CONTACT_TIMESTAMPS
SILVER.INBOX_GLOSSARY

-- GOLD: Semantic prefixes
GOLD.FCT_CONTACTS              -- Fact (enriched, granular)
GOLD.DIM_AGENT                 -- Dimension (current state)
GOLD.AGG_AGENT_DAILY           -- Aggregate (rolled up)
GOLD.V_AGENT_DASHBOARD         -- View (consumption)

Why full prefixes: - Multiple clients (consistency across clients is important) - Business users (non-technical folks need clarity) - Tableau (clear organization in data sources)


Special Case: When to Skip Prefixes

Dimensions that are really reference tables:

-- These could skip dim_ prefix (they're clearly reference data)
SILVER.INBOX_GLOSSARY          -- Not DIM_INBOX_GLOSSARY
SILVER.QUEUE_GLOSSARY          -- Not DIM_QUEUE_GLOSSARY
SILVER.SCORECARD_GLOSSARY      -- Not DIM_SCORECARD_GLOSSARY

Rationale: The word "GLOSSARY" already indicates it's reference data.

But if used in Gold as current state:

-- In Gold, use dim_ for consistency
GOLD.DIM_INBOX                 -- Current inbox config (from SILVER.INBOX_GLOSSARY)


Summary: Final Recommendation

Adopt Industry-Standard Prefixes

Layer Prefix Pattern Example
BRONZE {SOURCE}_{OBJECT} GLADLY_CONTACT_TIMESTAMPS
SILVER {OBJECT} CONTACT_TIMESTAMPS
GOLD Facts fct_{OBJECT} fct_contacts
GOLD Dims dim_{ENTITY} dim_agent
GOLD Aggs agg_{SUBJECT}_{GRAIN} agg_agent_daily
GOLD Views v_{PURPOSE} v_agent_dashboard

Rationale: - ✅ Industry standard (dbt Labs, GitLab, Kimball) - ✅ Self-documenting (grain and purpose clear) - ✅ Not redundant (prefix adds semantic info) - ✅ Easy to filter and organize - ✅ Consistent across clients

This is the best practice that balances clarity with convention.


dbt Implementation Example

# models/gold/warbyparker/schema.yml
models:
  - name: fct_contacts
    description: "Enriched contact-level facts. Grain: one row per contact event."
    config:
      tags: ['gold', 'facts', 'warbyparker']

  - name: dim_agent
    description: "Current agent dimension. Grain: one row per active agent."
    config:
      tags: ['gold', 'dimensions', 'warbyparker']

  - name: agg_agent_daily
    description: "Agent KPIs by day. Grain: one row per agent per day."
    config:
      tags: ['gold', 'aggregates', 'warbyparker']

  - name: v_agent_dashboard
    description: "Tableau dashboard view with targets and variance."
    config:
      materialized: view
      tags: ['gold', 'views', 'warbyparker']

Migration Path

If you want to migrate from current naming:

-- Current (no prefixes)
GOLD.CONTACTS
GOLD.AGENT_KPIS_DAILY
GOLD.AGENT_DASHBOARD

-- New (with semantic prefixes)
GOLD.FCT_CONTACTS              -- Enriched fact table
GOLD.AGG_AGENT_DAILY           -- Aggregated metrics
GOLD.V_AGENT_DASHBOARD         -- View for consumption

-- Migration strategy
CREATE OR REPLACE VIEW GOLD.CONTACTS AS SELECT * FROM GOLD.FCT_CONTACTS;
-- Keep old views for backwards compatibility, deprecate after 30 days

Questions to Finalize

  1. Do you prefer full prefixes (fct_, dim_, agg_) or short (f_, d_, m_)?
  2. Should we add prefixes to Silver (base_) or keep clean (no prefix)?
  3. Views: prefix (v_) or rely on materialization type (no prefix)?

My recommendation: Full prefixes (fct_, dim_, agg_, v_) for maximum clarity.