Handbook contents

Field guide · 2~12 min

Find your source

Your staging model reads from a raw model — a generated, cleaned view of one source table. Usually the raw model already exists and finding it takes a minute. When it doesn't, you need to understand how raw models come to exist at all.

How source data enters the project

Feeds land in the data lake databases — DATA_LAKE and DATA_LAKE__NCL— without dbt's involvement. The project's first contact with them is the raw layer, and the thing to understand is that nobody writes raw models by hand. There are around seven hundred of them, one per source table, each a near-identical view that quotes the source's columns and renames them to clean snake_case. Hand-writing them would mean seven hundred opportunities for drift and typos; instead, a pipeline generates them.

The pipeline works from a registry — scripts/sources/source_mappings.yml— which lists every database and schema the project reads. When the generation script runs, it queries Snowflake's own metadata for those schemas, writes the source declarations (the YAML that source() calls point at), and writes a raw model for each table. Run it again next month and everything is regenerated to match what Snowflake actually contains.

That regeneration is why the rule about generated files is absolute: an edit to anything under models/raw/ or to an auto_*.yml survives only until the next run. If a raw model is wrong, the fix belongs in the registry, the manual YAML or the generator — the places the pipeline reads from — never in its output.

How a Snowflake table becomes usable in dbt

The schema is mapped, but only tables a person lists are allowed in.

1 · Warehouse

The table lands

DATA_LAKE__NCL.ANALYST_MANAGED.OPENING_HOURS

Snowflake contains the new table and its columns.

upstream data
2 · Registry

The mapping says manual: true

scripts/sources/source_mappings.yml

That flag stops automatic discovery from admitting every table.

inspect; usually do not edit
3 · Source declaration

You add the table to YAML

models/sources/manual_analyst_managed.yml

The curated list is the approval step for this schema.

edit this file
4 · Raw layer

The pipeline writes SQL

models/raw/shared/raw_reference_opening_hours.sql

The approved table gets its generated 1:1 raw model.

generated: do not edit
switch routes · orange is the file you edit · grey files are generated

One wrinkle in the registry matters for the steps below. Most schemas are registered as automatic: every table in them gets a raw model, no decisions needed. A few are marked manual: true, which means tables are opted in one at a time — used for wide schemas where most tables are irrelevant to the project and generating hundreds of unused raw models would be noise. Whether your schema is automatic or manual decides how much work “adding a source” actually is.

First: establish what already exists

Start from the table's full DATABASE.SCHEMA.TABLE address — the schema matters as much as the table name, because it decides the route:

DATA_LAKE__NCL.ANALYST_MANAGED.OPENING_HOURS

Then search the project (Ctrl+P) three ways, in order: the likely staging name (stg_reference_opening_hours — if it exists, your work may already be done; reuse it), the likely raw name (raw_reference_opening_hours — this is the input you will ref()), and finally the bare table name across the repo, which catches a source prefix you did not guess. If the raw model exists, preview it and you are done with this page:

dbt show -s raw_reference_opening_hours

If there is no raw model

Then the table has never been brought into the project, and the registry tells you how big a job that is. Open scripts/sources/source_mappings.yml and search for the schema:

What the registry saysWhat that means
Schema present, no manual: trueAutomatic — the table should appear on the next generation run with no YAML edits at all. Just run the pipeline.
Schema present, marked manual: trueOpt-in — add one table block to that source's manual_*.yml, then run the pipeline.
Schema absentThe project has never read this schema. Registering one is a governance decision as much as a technical one — pair with the team rather than adding a mapping alone.

For the manual case, the block you add is small. Find the source in the matching models/sources/manual_*.yml and add your table inside its tables: list, copying a neighbouring block so the indentation is right:

models/sources/manual_analyst_managed.yml
- name: OPENING_HOURS
  identifier: '"OPENING_HOURS"'
  columns:
  - name: SITE_CODE
    data_type: TEXT
  - name: DAY_OF_WEEK
    data_type: NUMBER(2,0)

Run the generation and check what it did

python scripts/sources/run_all_source_generation.py

The script signs into Snowflake (a browser window opens) and runs four stages: it queries the metadata, extracts it, writes the source YAML, and writes the raw models. Because it regenerates from live metadata, its output can include changes you did not cause — a column added to someone else's feed since the last run, for example. So the check afterwards is a genuine review, not a formality:

git status --short
git diff -- models/sources models/raw
dbt parse
dbt show -s raw_reference_opening_hours

You are confirming four things: the expected source YAML changed, your raw model appeared in the right domain folder, the project still parses, and the preview shows the cleaned snake_case columns you will build on. If the diff includes changes to sources you never touched, ask the team about them before bundling them into your PR — they are probably legitimate drift, but that is a decision to make knowingly.

When the input is a seed

Small, team-owned reference data — a mapping of status codes, a list of thresholds — can skip the source machinery entirely and live as a CSV under seeds/. dbt seed loads it into the warehouse and models ref() it like anything else. The boundary: a seed is reference data that belongs to the project's logic and changes by review, the way code does. An extract, a feed, or anything at patient level is not a seed, however convenient the folder looks.

Before writing the model