River
Y CombinatorBacked by Y Combinator

Free template

Data Dictionary and Metric Catalog Template

Sheets for every column in your database and every metric you report, a log for metrics teams calculate differently, and guides to defining them well.

Free download · No account needed

What you get

Pack of 8 files: 5 documents, 3 spreadsheets

Data Dictionary and Metric Catalog Template
  • How Coverage Is CountedDocument
  • Definition StandardDocument
  • Ownership ModelDocument
  • Worked DictionaryDocument
  • Ambiguity Resolution NoteDocument
  • Field RegisterSpreadsheet
  • Metric Definition RegisterSpreadsheet
  • Ambiguity LogSpreadsheet
RiverData Dictionary and Metric Catalog Template

Field Register

One row per column that exists, not one row per column somebody chose

The denominator is read out of the warehouse. A column added on Tuesday is an undefined row on Tuesday, and coverage can fall without anybody deleting anything.

The columns every dictionary has

Table, column, data type transcribed verbatim from the engine, owner, consumers, grain. Nothing controversial, and nothing here decides whether the row is worth anything.

Definition, and then Definition Class

The prose, and then the verdict on the prose. Meaning, Restates Name, Storage Only, Contradicted, Empty. The test is mechanical rather than editorial: could this have been written without opening a query. Only Meaning counts toward real coverage.

Warehouse Comment, verbatim

What the database actually holds for that column, right now, including empty. A definition written in a transformation project does not reach the warehouse unless somebody turned persistence on for that resource, so the analyst reading the column in a console sees a different thing than the sheet does. Comment State reconciles them as Matches, Stale, or Absent, and stale is the worse one.

Reads, First Seen, Undefined Days

Read count over ninety days, the date the column first appeared, and the gap between that date and the day a real definition landed. Sort by reads descending, filter to class not Meaning, and the work queue is the first forty rows. This is the section that turns a thirteen-hundred-row backlog into an afternoon.

Notes

Where the definition came from, which model populates the column, and what would settle it if nothing does. An orphan row keeps its prose here rather than being deleted, because most orphans are renames and the definition usually still holds.

Page 1 of 1281 words

How to create a data dictionary

A data dictionary is a reference that lists every column in a database or dataset and explains what each one holds. Each entry gives the table and column name, the data type, an owner and a plain definition. That definition says what the value means, what sets it, what it leaves out and what one row represents. To create one, export the database's own column list, then define the most-read columns first.

Most of the work is in the definitions, and the test is blunt: if someone could have written one from the column name alone, it isn't finished.

Two developers work at desktop monitors in a bright office, one screen showing lines of code
Define a column from the code that fills it, not from its name. Photo: Compagnons on Unsplash

List every column from the database

Get the full column list before you write a word. Most SQL databases include an information schema, built-in views that list every table and column you can access, so one query returns them all. PostgreSQL's manual notes that it is defined in the SQL standard1 and can be expected to be portable. Oracle is an exception: it keeps the same list in its ALL_TAB_COLUMNS view.

Write the scope at the top of the dictionary, such as the reporting tables analysts query rather than every staging table. Every column in that scope gets a row, described or not. A dictionary that lists only the columns someone chose to describe always looks complete, because nobody adds a row they don't plan to fill.

The US Geological Survey's guidance on what a data dictionary can include2 lists names, definitions, data types, allowed values, missing-data codes and business rules. For a warehouse, six fields do most of the work.

What each entry records

FieldWhat to write
NameThe table and column, spelled exactly as in the database
Data typeCopied from the database, so the definition never repeats it
DefinitionWhat the value means, what sets it, what it excludes and its grain
Database commentThe column's comment in the database, copied word for word
OwnerOne named person who controls the code that fills the column
ReadsReads in the last 90 days, if your warehouse logs them

Start with the most-read columns

You won't define 1,000 columns in a week, so let usage decide the order. Snowflake, the cloud data warehouse, keeps a year of access history down to the column3 in Enterprise Edition and above. Other warehouses keep query history too, though not always column by column. Sort by reads and work down the ones without a real definition.

The top of that list is often join keys, status codes and timestamps. Their names look too obvious to explain, which is exactly why nobody did. If your warehouse doesn't log reads, start with the columns your dashboards and recurring reports use.

Write definitions that explain something

A useful definition answers four questions in one to three sentences. What does the value mean to the business? Which event or calculation sets it? What does it exclude? And what does one row stand for, its grain? The Kimball Group calls declaring the grain the pivotal step in a dimensional design4: it establishes exactly what a single fact table row represents.

Watch for definitions that restate the name. The Australian Government's API playbook, whose principles draw on the ISO 11179 standard, warns that simply restating the name in sentence form5 doesn't describe the concept. Its example is a field called Country Name. Instead of "Name of a country," it suggests "The commonly known, short name that identifies a country," which rules out the long form.

ExampleOne column, before and afterAn illustrative example written for this guide

Column: shipment_created_at

Before: The date and time the shipment was created.

After: The moment the shipper's booking was accepted, stored in UTC. Set once and never updated; a rebooking creates a new row. Excludes quotes that were never booked. One row per shipment.

  • Restates the name. It only spells out shipment_created_at in longer words.
  • Answers the real questions. It names the event that sets it, the time zone, what's left out and the grain.

Check the code, then publish

Read the code that fills each column, most-read first, before you trust its definition. A definition that contradicts the code is worse than a blank, because people believe it. If a flag documented as "true once the customer signs" is really set when the truck reaches the yard, every report using it counts the wrong event.

Then put definitions where analysts look, including the comment stored on each column, which many SQL tools display. If you write them in dbt, check one setting. dbt Labs, which makes the tool, says copying descriptions into the database as comments is disabled by default6. Until you turn it on, anyone browsing the warehouse sees none of them.

Define each metric once

Metrics need entries of their own, because a formula can drift even when every column is defined. In 2021, Uber's engineers showed one metric, Shopping Sessions, at 6.53 million in one tool and 6.20 million in another7 for the same city and period. One tool's query used stale filters that missed some rider states.

Give each metric one entry: the question it answers, the numerator, the denominator, the grain, the clock and where the official query lives. Spell out every filter, and let the clock name the events that start and stop the measured time. Start with numbers that reach a contract, a board pack or a weekly business review.

If a metric already exists in several versions, find them all, name the choices where they differ, and compute each for the same period. Put counts beside the percentages so anyone can check them.

One on-time rate, four versions (made-up figures for one month)

Where it appearsClock stops atSecond attemptsOn time / deliveriesRate
Operations dashboardArrival at the yardLeft out39,392 / 41,86094.1%
Customer SLA reportCustomer's signatureLeft out38,220 / 41,86091.3%
Carrier scorecardArrival at the yardCounted39,392 / 43,19091.2%
Board packCustomer's signatureCounted38,220 / 43,19088.5%

41,860 counts first attempts only; 43,190 adds 1,330 second attempts. Against a 92% contract target, only the operations dashboard passes. The SLA report and carrier scorecard land 0.1 points apart while disagreeing on both choices.

Two yes-or-no choices produced four live numbers and a 5.6-point spread. Let the metric's owner pick one, and record the reason in terms of the question the metric answers, not which number looks better.

Keep the data dictionary current

Assign every column one owner, the person who controls the code that fills it, and every metric one owner, whoever gets asked why the number moved. Ask owners to update a definition in the same change that alters the code. The USGS guidance is plain: when data structures change, update the dictionary2.

Re-run the column query monthly. Add new columns as empty rows, and don't define them from their names. A row whose column vanished is often a rename, so move its definition to the new name before closing it, especially after a technical migration.

Report coverage three ways and quote them together, since the first flatters on its own. The template's made-up dictionary, which claimed 95%, scores:

  • Raw, 34%: the share of columns in scope with any description
  • Real, 15%: the share with a definition that passes the tests above
  • Read-weighted, 9%: the real share, weighted by how often each column is read

Before you share it

  • Every column in scope has a row, pulled from the database
  • No definition restates its column name
  • Each definition says what sets the value, what it excludes and its grain
  • The most-read columns are defined first
  • Every column and metric has one named owner
  • Each metric has one official query, and other versions are listed with their numbers

If the same fields appear in your API, define them here and link to them from your API documentation. For a faster start, choose Edit with AI at the top of this page. River reads the schema and documents you send, classifies every existing definition and reports coverage all three ways.

How to use this template

Read How Coverage Is Counted and the Definition Standard, name a default owner in the Ownership Model, then fill the Field Register from your database's column list. Sample rows from a made-up freight company show what each state looks like, so clear them once you've read them.

Or choose Edit with AI and send what you have, such as a schema export, an old dictionary or a list of disputed metrics. River reports how many columns exist before it writes anything, then classifies each existing definition and shows which heavily read columns still need one.

  1. Download it or open it in River

    Get the five Word documents and three CSV sheets free, or open the template in River with Edit with AI.

  2. Send your column list

    Attach a schema export or information-schema query result, plus any old dictionary, transformation project or BI export you have.

  3. See your real coverage

    River classifies each existing definition, reports coverage three ways and lists the most-read columns that still need a definition.

  4. Define, compare and sweep

    Ask River to define a column from its code, compare versions of a disputed metric, or find new columns each month.

What's in the template

Coverage of 34.4 percent, or 9.3 percent, from one registerThe Field Register's coverage arithmetic, the Ambiguity Log, and the new-column sweep.
Data Dictionary and Metric Catalog Template
RiverCoverage

Coverage, three ways

Latimer Freight, a fictional freight brokerage. 108 tables and views, 1,412 columns, and an inherited dictionary that reported 95 percent.

FractionNumeratorDenominatorResult
The contractor's sheet486 described rows512 rows in the sheet94.9%
Raw coverage486 with any description1,412 columns in the warehouse34.4%
Meaning-class coverage212 that survive the test1,412 columns in the warehouse15.0%
Read-weighted coverage296,524 reads on a defined column3,184,000 column reads, 90 days9.3%
Definition ClassColumnsWhy it does not count
Meaning212It counts. Says what the value represents, what sets it, what it excludes, and at which grain.
Restates Name189Content words already in the column name. shipment_created_at as "the date and time the shipment was created."
Storage Only71Transcribed from the schema. The data type column already carries it.
Contradicted14A real business sentence the code disagrees with. Reads as the best rows in the sheet.
Empty926No description at all.

The 25-point gap between raw and read-weighted is the finding. Warehouse reads are skewed hard: the 50 most-read columns carry 61 percent of all reads, and 3 of those 50 have a meaning-class definition. They are join keys, status enums, and timestamps whose names look self-explanatory, which is exactly why nobody wrote them down.

Twenty-six of the 512 rows describe a column that no longer exists. Renames from a migration eleven months ago. Measured against itself a dictionary always improves, and part of that improvement is prose about fields nobody can query.

Sort by reads descending, filter to class not Meaning, work down. Forty-seven rows moves the third number further than the last fourteen months moved the first.

RiverOne Metric, Four Numbers

on_time_rate, March 2026

Four live implementations of one metric name. 43,190 delivery events, 1,330 of them second attempts, 41,860 first attempts. The customer contract commits to 92 percent.

SurfaceClock stops atSecond attemptsCalculationRatevs 92%
Operations dashboardyard arrivalexcluded39,392 / 41,86094.1%clears
Customer SLA reportsignatureexcluded38,220 / 41,86091.3%misses
Carrier scorecardyard arrivalcounted39,392 / 43,19091.2%misses
Board packsignaturecounted38,220 / 43,19088.5%misses

One of the four clears the commitment. The spread is 5.6 points, and the one that clears is the one on the wall in the operations room. Two binary clauses, which event stops the clock and whether a second attempt is a separate event, with all four combinations live. Four queries is a mess. Two clauses is a decision.

The customer SLA report and the carrier scorecard land 0.1 points apart while disagreeing on both clauses. Anybody comparing those two dashboards would conclude the numbers reconcile. They coincide, for one month, and they separate as soon as the second-attempt rate moves. It is the whole argument for logging the clause rather than the difference.

The board pack calculation was adopted, and it is the lowest of the four. The note records that this was not the reason, which is what stops the choice being reopened as a presentational one six weeks later. Eleven metric names on this warehouse resolve to 27 distinct implementations.

A clause nobody can price is a clause nobody prioritizes. Every row carries the number its implementation produces for one agreed period.

RiverNew Columns

The sweep that keeps it alive

The same 90 days, run against the warehouse rather than against the sheet. A dictionary decays because its row list is fixed and the warehouse's is not.

What changedCountWhat happens to the row
New columns in the warehouse63Added as Empty, with First Seen. No definition written from the name.
New and already read by a dashboard9Live risk rather than backlog. Ranked first.
New and present in the old dictionary0Not an oversight. Its row list was fixed fourteen months ago.
Orphans, column gone26Kept. Check for a successor column and move the prose across before closing.
Type changed under an existing definition4Flagged where the definition mentions a range, a precision, or a unit.

Nine of the 63 are already feeding something. One of them, tender_rejection_reason, is 34 days old and sits behind two tiles on a carrier performance board. A column that is undefined and unread is a backlog item. A column that is undefined and already on a dashboard is a different thing.

Coverage going down is the correct behavior. Sixty-three new columns and no new definitions moves all three numbers the wrong way, and a register that cannot do that is a register measuring itself. Say it out loud in the sweep so nobody reads it as a regression in the documentation.

Median age of the 1,200 columns with no meaning-class definition: 412 days. That single figure is the honest answer to whether the catalog is being kept up, and it is the one to put in front of whoever asked for one.

Orphans are evidence, not waste. Somebody understood that field well enough to write about it, and most of the time the column was renamed rather than removed.

  • How Coverage Is CountedWhere the column count comes from, the five definition classes and the three coverage figures.
  • Definition StandardThe four parts every column definition needs, the six a metric needs, and before-and-after examples.
  • Ownership ModelWho owns a column, who owns a metric, the default owner and how disputes escalate.
  • Worked DictionaryA made-up freight company's warehouse classified end to end, with its coverage figures and metric dispute.
  • Ambiguity Resolution NoteA one-page note that settles a disputed metric and records why the chosen version won.
  • Field Register sheetOne row per database column, with its type, definition, class, database comment, owner, reads and first-seen date.
  • Metric Definition Register sheetOne row per metric: grain, numerator, denominator, filters, clock, owner, official query, versions found and status.
  • Ambiguity Log sheetOne row per version of a disputed metric, with the number it gives for one agreed period.

Common questions

What should a data dictionary template include?

One row per column, with the table and column name, data type, a plain definition, an owner and the comment the database stores. Add how often each column is read, so you know where to start. A separate metric catalog covers anything calculated, such as an on-time rate or monthly churn.

What is the difference between a data dictionary and a data catalog?

A data dictionary explains the columns of one database or dataset: names, types, meanings and owners. A data catalog is an inventory of data across many systems, usually software that gathers metadata automatically so people can search it. A catalog can show that a description exists, but not whether it explains anything.

What is a metric catalog?

A metric catalog, sometimes spelled metric catalogue, lists each business metric once: the question it answers, its numerator, denominator, filters, grain, clock, owner and official query. Its job is to stop two teams reporting different numbers under one name, and it records every version of a disputed metric until the owner picks one.

How often should you update a data dictionary?

Change a definition at the same time as the code behind its column, and pull a fresh column list about once a month to catch new and renamed columns. A full annual review of every row is rarely worth it. Checking new columns, heavily read gaps and definitions that contradict the code is a better use of the time.

Can I use this template in Excel or Google Sheets?

Yes. The three sheets are CSV files that open in Excel, Google Sheets or Numbers, and the five documents are Word files. You don't need dbt or Snowflake either: the method works with any database that can list its columns. If yours doesn't log reads by column, rank columns by how often dashboards and reports use them.

Is this data dictionary template free?

Yes. Download the five Word documents and three CSV sheets with no signup. The sheets come with sample rows that show each state a row can be in, so you can see how they work before clearing them. Edit with AI opens the same files in a free River workspace.

What does Edit with AI do?

It opens the template in a free River workspace and asks for what you have. That can be a schema export, an old dictionary, a transformation project or a list of disputed metrics. River counts every column, sorts each existing definition into one of five classes, reports coverage three ways and never writes a definition from a column name.

Sources

  1. PostgreSQL. “The Information Schema.” postgresql.org (opens in a new tab)

  2. U.S. Geological Survey. “Data Dictionaries.” usgs.gov (opens in a new tab)

  3. Snowflake Documentation. “ACCESS_HISTORY view.” docs.snowflake.com (opens in a new tab)

  4. Kimball Group. “Grain.” kimballgroup.com (opens in a new tab)

  5. Australian Government. “Writing good data definitions.” playbook.api.gov.au (opens in a new tab)

  6. dbt. “persist_docs.” docs.getdbt.com (opens in a new tab)

  7. Uber. “The Journey Towards Metric Standardization.” uber.com (opens in a new tab)

Written by

Chandler Supple

Co-founder & CEO, River

Chandler has spent the last six years working in AI, building tools for millions of users and Fortune 100 companies. In 2025, he co-founded River to build a new kind of operating system for AI agents.

Reviewed by

Brian Joseff, Co-founder, River