3.4 Unity Catalog Naming Conventions, Environment Isolation, & Data Granularity
Key Takeaways
- Unity Catalog object names may not exceed 255 characters and may never contain a period, a space, a forward slash, an ASCII control character, or the DELETE character; Unity Catalog stores all object names in lowercase.
- A hyphen is legal in a Unity Catalog name but forces every SQL reference to be backtick-escaped, which is why production naming standards use underscores exclusively.
- The catalog is the isolation boundary: a catalog-per-environment layout (dev, staging, prod) plus workspace-catalog bindings prevents a development workspace from ever resolving a production table name.
- Table granularity is the definition of what one row represents; declare it in the table COMMENT because grain determines the SCD type, the clustering keys, and whether an aggregate can ever be recomputed.
- Granularity is a one-way door downstream: a finer grain can always be aggregated later, but a coarser grain permanently discards the detail needed to answer a new question.
3.4 Unity Catalog Naming Conventions, Environment Isolation, & Data Granularity
DP-750 Exam Focus: Two blueprint bullets meet here - "Apply naming conventions based on requirements, including isolation, development environment, and external sharing" and "Choose granularity on a column or table based on requirements." Both look like style questions and are actually architecture questions: names encode the isolation boundary, and grain encodes what the table can and cannot answer.
1. The Hard Rules Unity Catalog Enforces
Before any convention, these are constraints the platform itself imposes on all Unity Catalog object names:
| Rule | Detail |
|---|---|
| Maximum length | 255 characters |
| Forbidden characters | Period (.), space, forward slash (/), all ASCII control characters (hex 00-1F), and the DELETE character (hex 7F) |
| Case handling | Unity Catalog stores all object names as lowercase. Column names preserve their casing, but queries against Unity Catalog tables are case-insensitive. |
| Escaping | Names containing special characters such as a hyphen must be backtick-escaped in every SQL statement |
-- Legal, but every future reference needs backticks:
CREATE CATALOG `retail-prod`;
SELECT * FROM `retail-prod`.sales.orders;
-- Illegal: space and forward slash are rejected even inside backticks
CREATE CATALOG `retail prod`; -- ERROR
-- The convention that avoids the problem entirely:
CREATE CATALOG retail_prod;
SELECT * FROM retail_prod.sales.orders;
Legacy contrast. Objects created in the legacy
hive_metastorecatalog are stricter still: schema, table, view, and function names there may contain only alphanumeric ASCII characters and underscores, and anything else raisesINVALID_SCHEMA_OR_RELATION_NAME. Unity Catalog is more permissive, which is exactly why an explicit convention matters.
Delta Lake Column-Name Restriction
Delta tables without column mapping (delta.columnMapping.mode = name) cannot have column names containing a space, comma, semicolon, curly brace, parenthesis, newline, tab, or equals sign. Enabling column mapping lifts the restriction but upgrades the table protocol - which, as Section 2.5 notes, can lock out older readers.
2. A Naming Standard That Encodes Isolation
Unity Catalog's three-level namespace (catalog.schema.object) gives you exactly one strong isolation boundary - the catalog - and one organizational boundary - the schema. A working convention:
| Object | Pattern | Example |
|---|---|---|
| Catalog (environment-first) | {env}_{domain} | prod_retail, dev_retail, stg_retail |
| Schema (medallion layer or subject) | {layer} or {subject} | bronze, silver, gold_finance |
| Table | {entity} or {entity}_{grain} | orders, orders_daily_agg |
| Streaming/CDC target | {entity}_scd2 or {entity}_current | customers_scd2 |
| Volume | {purpose}_{source} | landing_pos_files, checkpoints_ingest |
| External location | {env}_{storage_account}_{container} | prod_adlsretail_bronze |
| Storage credential | {env}_{access_connector} | prod_mi_retail |
| Connection (federation) | {source_system}_{env} | sqlserver_orders_prod |
| Delta Sharing share | {provider}_{consumer}_{subject} | retail_partnerco_sales |
| Delta Sharing recipient | {external_org} | partnerco |
| Account group | {env}_{domain}_{role} | prod_retail_readers, prod_retail_engineers |
Why Environment Belongs in the Catalog Name
Putting the environment in the catalog rather than the schema or the table gives you three properties at once:
- Fully qualified names differ across environments, so a notebook promoted from dev to prod fails loudly if someone forgot to parameterize the catalog, instead of silently writing dev data into a prod table.
- Privileges are grantable at the isolation boundary.
GRANT USE CATALOG ON CATALOG prod_retail TO prod_retail_readersscopes an entire environment in one statement. - Workspace bindings become meaningful. A catalog can be bound to specific workspaces so that
prod_retailis not even resolvable from the development workspace:
-- Restrict a catalog to named workspaces (also available in Catalog Explorer -> Workspaces)
ALTER CATALOG prod_retail SET WORKSPACE BINDINGS ('<prod-workspace-id>');
Combine this with a Databricks Asset Bundle target variable so the catalog name is injected per environment rather than hardcoded (see Section 12.3).
Naming for External Sharing
Delta Sharing objects are read by people outside your organization, so their names leak information. Two rules:
- Never encode internal system names, cost centers, or project codenames in share and recipient names - a share called
finco_project_bluebird_m_and_atells a partner more than intended. - Name the relationship, not the storage.
retail_partnerco_salesis stable when the underlying table moves;adls_prod_container3_exportis not.
3. Choosing Table Granularity (Grain)
Grain is the answer to one sentence: "one row in this table represents exactly one ____." If you cannot finish that sentence in a few words, the table has no defined grain and its aggregates cannot be trusted.
| Layer | Typical grain | Why |
|---|---|---|
| Bronze | One row per source record or event, as delivered, with ingest metadata | Preserves replay ability; never aggregate in bronze |
| Silver | One row per business entity or per validated transaction | Deduplicated, conformed, type-cast, joined to reference data |
| Gold | One row per reporting grain, e.g. one row per store per day | Pre-aggregated for BI latency; grain matches the dashboard |
The One-Way Door
A finer grain can always be rolled up later. A coarser grain permanently destroys the detail needed to answer a question nobody has asked yet. If a gold table stores revenue per store per day, no query can ever recover revenue per hour. Practically:
- Keep bronze and silver at the finest grain the source provides.
- Aggregate only in gold, and only to a grain a stakeholder has actually requested.
- Build additional gold tables at different grains rather than coarsening an existing one.
Column Granularity
The same decision applies within a column:
| Column | Coarser | Finer | Trade-off |
|---|---|---|---|
| Time | order_date (DATE) | order_timestamp (TIMESTAMP) | A DATE column cannot support hourly SLA reporting |
| Geography | country_code | postal_code | Postal-level detail may be personally identifying and require a column mask |
| Product | category_id | sku | SKU explodes cardinality but enables assortment analysis |
| Money | revenue_usd rounded | revenue_usd DECIMAL(18,4) | Rounding early makes reconciliation with source systems impossible |
Finer column granularity raises cardinality, which is exactly the input to the clustering decision in Section 8.3: high-cardinality, high-selectivity filter columns are good liquid clustering keys, while low-cardinality columns are usually better left unclustered.
Declare the Grain in Metadata
A grain that lives only in a design document is a grain that will be violated. Put it where every consumer and every discovery tool can read it:
COMMENT ON TABLE prod_retail.gold.store_sales_daily IS
'Grain: one row per store_id per business_date. Revenue is net of returns. Late-arriving
sales are restated for 7 days after business_date.';
ALTER TABLE prod_retail.gold.store_sales_daily
ALTER COLUMN business_date COMMENT 'Store local calendar date, not UTC ingest date.';
Section 6.5 shows how these descriptions feed Catalog Explorer search and AI/BI Genie.
4. Exam Traps
- "Add the environment to the table name" (
orders_prod) is the wrong answer. Environment belongs in the catalog so it can be bound and granted. - Backticks do not rescue a space or a period. Those characters are rejected outright; only characters like hyphens are merely inconvenient.
- Aggregating in silver to "save storage" is a grain violation; the correct answer is a gold table at the requested grain.
- Case sensitivity: Unity Catalog lowercases object names, so
Ordersandordersare the same table. Column casing is preserved but queries are still case-insensitive.
A platform team wants a naming standard that prevents a notebook promoted from development to production from ever writing into the wrong environment, and that lets them grant an entire environment to a group in a single statement. Where should the environment identifier live?
A gold table is defined as one row per store per calendar day. Six months later, operations asks for revenue by hour to staff shifts. What does the existing design require?
Which of the following catalog names will Unity Catalog reject outright, even if the name is enclosed in backticks?