# A searchable data catalog your business teams actually open

> Every dbt model gets a page with a plain-English description, clickable lineage, and live freshness, so nobody has to ask what a table means.

- Workflow type: app
- Services: dbt Cloud, Snowflake
- Categories: Operations, Engineering
- Published: 2026-08-21

## What it does

- Builds a browsable catalog straight from your production dbt job, so every model gets its own page with description, columns, tags, and owner
- Lets people search by metric or column name instead of model name, because business users look for 'churn' rather than fct_customer_retention
- Shows when each table last built successfully plus a live row count and newest timestamp, so a viewer can tell at a glance whether the numbers are current
- Adds a Help me find a table box where you describe the analysis you are running and an assistant writes back the two or three best models with sample SQL and caveats

## What you'll need

- A dbt Cloud account and the production job you want the catalog built from
- A Snowflake connection with read access to the tables that job builds, used only for row counts and freshness
- Ideally your dbt job set to generate documentation when it runs. If it does not, the catalog still works and simply hides column types
- Descriptions and owners filled in on your dbt models, since that is the copy business users read

## Prompt

I want an internal data catalog app that our business teams open when they need to know what a table means, so they stop pinging the data team to ask. It is read only and search first: someone lands on it, types the metric they care about, and walks away knowing which model to query and whether the numbers in it are current.

Build the catalog from the latest artifacts of our production dbt job. Use the dbt Cloud Retrieve Job Artifact operation twice against a configured account id and job id, once for manifest.json and once for catalog.json. That operation returns the latest matching artifact for the job, which is how the catalog stays current without any schedule. Artifacts default to the last run step's output, so expose a step setting and pass it when our docs generate step is not last. Every dbt Cloud response wraps the payload as { status, data }, so read the artifact out of data. Parse manifest.json into a catalog index of models covering unique id, name, database and schema and alias, description, tags, owner and other meta fields, column definitions, and the depends_on and child map entries that give lineage. Give the app a Refresh catalog button that re-fetches both artifacts and rebuilds the index.

catalog.json only exists if the job runs docs generate, so handle its absence gracefully. If the catalog artifact request fails or comes back empty, build everything from manifest fields alone, hide the column type and warehouse statistic columns rather than showing blanks or error text, and put a small note on affected model pages saying types are unavailable until the job generates documentation. A missing catalog artifact must never break the catalog build.

The home view is a search box plus results. Search has to cover model names, descriptions, and column names together, because business users search for the metric they want rather than the model name. Someone typing churn should find a model whose description mentions churn and a model with a churn_flag column, and each result row should say why it matched. Show tags, owner, and a freshness badge on every result. Above the results, show the viewer's pinned tables as their own home view.

Each model gets its own page showing the description, the full column list with names, types, and column descriptions, tags, owner, the database and schema and table name, and lineage. Render upstream and downstream lineage as clickable links to the other model pages so somebody can walk the graph one hop at a time. Upstream comes from the model's depends_on nodes and downstream from a reverse index built across the manifest. Include sources as lineage endpoints, and render a node that has no page of its own, such as a source or a seed, as a plain labelled item rather than a dead link.

On the model page, show when the model last built successfully. Use dbt Cloud List Runs filtered to the configured job, keep only runs whose status is 10, which means Success, and take the most recent by finished time. Use Retrieve Run for the detail on that run: finished time, duration, and a link back to the run in dbt Cloud. Fetch this once per catalog load and reuse it across model pages instead of calling it per model.

Next to the build time, show live warehouse numbers for the table: the current row count and the newest timestamp in it. Get both with the Snowflake Execute SQL Statement operation, running a read only SELECT against the relation the manifest gives for the model. Snowflake uppercases unquoted identifiers, so pass database, schema, and table in the case Snowflake stored them and pass the warehouse explicitly. For the newest timestamp, pick the model's freshness column with a heuristic over its column list, preferring names like updated_at, _loaded_at, dbt_updated_at, or created_at, and let someone override the choice per model in settings. Skip the query entirely for ephemeral models, which have no table behind them. If the query fails on permissions or a missing relation, show row count unavailable on the page and keep everything else rendering.

Add a Help me find a table box where a viewer describes, in plain language, the analysis they are trying to run. Submitting it kicks off a background agent. The agent searches the catalog index for candidate models across names, descriptions, columns, and tags, checks each candidate's freshness using the last successful build time plus a live row count and newest timestamp from Snowflake, and then writes a recommendation back into the app. The recommendation names the two or three best models, links to each model page, includes sample SQL the viewer could run or hand to an analyst, and calls out caveats about what each model excludes, such as filtered test accounts, a restricted date range, or a grain that does not match what was asked for. Recommendations land in the app as records holding the original question, the answer, and a timestamp, visible on the home view and on a Recommendations list, so the same question does not get answered twice from scratch.

Let every viewer pin favorite tables. Pins are per person rather than shared, and they sit at the top of that person's home view with their freshness badges, so a viewer sees the state of the tables they care about the moment they open the app.

Settings hold the dbt Cloud account id, the job id, the optional artifact step, and the Snowflake warehouse and role defaults. The app stays read only throughout: nothing writes to dbt or to the warehouse, and the only queries are counts and timestamp lookups. Write the page copy for a business reader rather than an analytics engineer, leading with what a table means and whether it is current, keeping the technical detail available but secondary.

## How to customize

- Point it at a different dbt job, or at a specific step within the job if documentation gets generated before the final step
- Change which column each table uses for its freshness timestamp, or switch off live warehouse checks for very large tables
- Decide what leads on a model page: descriptions and owners for business viewers, or columns and lineage for analysts

## FAQ

### Do our business users each need a dbt Cloud seat?

No. The app connects to dbt once, through a connection you set up as an admin. Everyone else just opens the app and searches, so the people who only need to look something up never consume a seat.

### What happens if our dbt job does not generate documentation?

The catalog still builds. Model names, descriptions, tags, owners, and the full lineage graph all come from the project definitions, which are always available. Column types and warehouse statistics are hidden with a short note instead of showing blanks, and they appear automatically once you turn documentation generation on for the job.

### Does the catalog stay up to date on its own?

Yes. It always reads the newest output from your production job, so a new model shows up the next time the app loads or when someone hits Refresh. There is no sync schedule to maintain and nothing to re-export.

### Can people change data or run their own queries from here?

No. The app is read only. The only thing it runs against the warehouse is a row count and a newest-timestamp lookup on the table you are viewing, so it is safe to hand to anyone in the company.

### How is this different from exporting our dbt docs somewhere?

An export gives you static pages that are stale the moment they are written. This is a live surface: search covers column names, lineage is clickable so you can walk from a dashboard table back to its sources, freshness is checked against the warehouse in real time, and you can ask an assistant which table fits the analysis you are about to run.

Use this prompt in General Input: https://www.generalinput.com/prompts/a-searchable-data-catalog-your-business-teams-actually-open