When should reference data live as a dbt seed rather than a pipeline-loaded table?
answer
- ask who owns the truth
- is there already a system of record
- small, static, safe, and reviewable
- pull request as the change process
basics
~20 sSeed it when the analytics team is the system of record and the data is small, slow-moving and non-sensitive, so a pull request is the right change process. Ingest it when an upstream system already owns the data or it changes often.
solid answer
~50 sThe deciding question is ownership: is there an upstream system of record? If a business application already holds the mapping, seeding it forks the truth and guarantees drift, so ingest it. If the only authoritative copy is a spreadsheet an analyst maintains, a seed turns that spreadsheet into reviewed, versioned, auditable code — `git log` answers who changed the region mapping and when, and CI tests the change before it reaches production. Then apply the practical filters. **Size**: seeds load through generated `INSERT` statements and run in every build and CI job, so keep them to hundreds or a few thousand rows. **Change rate**: daily churn makes a commit-per-change workflow friction. **Sensitivity**: a seed is plaintext in git history forever, so no personal data or secrets. **Editor**: if the maintainer cannot open a pull request, a seed makes them dependent on someone who can — that is the point at which a small internal app or a sheet-sync into a real source table beats both options.
code
yaml · 15 linesversion: 2
seeds:
- name: country_to_region
description: >
Analytics-owned mapping of ISO country code to sales region.
Owner: revenue-analytics. Change via pull request.
config:
column_types:
country_code: varchar(2)
columns:
- name: country_code
data_tests: [unique, not_null]
- name: sales_region
data_tests: [not_null]go deeper
Know the simple rule of thumb: seeds are for small, static, analytics-owned reference data, and anything with a real upstream system belongs in the ingestion pipeline.
Explain the concrete costs on each side — insert-based loading and repo weight for seeds, pipeline effort and latency for ingestion — and apply them to a specific mapping.
Lead with ownership and the change process, cover sensitivity and who can edit, and show how you would test and document whichever home you choose so the mapping stays trustworthy.
Own the policy across the organisation: what may live in the repository at all, how reference data is governed and swept, and the migration path when a seed outgrows a pull-request workflow.
## Reframing the question This is not really a dbt question; it is a question about where a dataset's system of record should live and who is allowed to change it. dbt just gives you two homes for the answer — a CSV in the repo, or a table landed by the ingestion pipeline and declared as a source. ## The first filter: is there already an owner? If an operational system holds the data, ingest it. A product catalogue lives in the commerce platform; an employee roster lives in the HR system; a customer's account tier lives in the billing service. Copying any of those into a CSV creates a second copy with no synchronisation, and it will diverge — not maybe, but on a schedule set by how often someone remembers to re-export. The failure is quiet and shows up as reports that disagree with the operational tool. If no system owns it — the mapping exists only because analytics needs it — a seed is genuinely the better home, because the alternative is an unversioned table someone maintains by hand with `INSERT` statements in a console, which has no history, no review and no reproducibility across environments. ## What a seed actually buys you - **Auditability.** Every change is a commit with an author, a timestamp and, if you require reviews, an approver. "Why did EMEA revenue jump in March?" becomes a diff. - **Reproducibility.** A fresh dev or CI environment has the reference data automatically, because it is in the repo. Hand-maintained tables have to be copied around. - **Testability.** The change runs through CI: uniqueness of the key, referential coverage against the dimension it maps, a row-count sanity check. You find the typo before production does. - **Atomicity with code.** A mapping change and the model change that depends on it ship in one pull request and can be reverted together. ## What a seed costs - **Load mechanics.** Seeds load as generated `INSERT` statements. Large files make every full build and every CI run slower for everyone on the team. - **Repository weight.** Data in git means data in git forever, including every intermediate version. - **Access.** The maintainer must be able to open a pull request. For a finance analyst who owns the fiscal calendar, that is often a real barrier, and the workaround — an engineer edits the CSV on their behalf — inserts a person into a routine business process. - **Latency.** Deploy cadence becomes change cadence. If the mapping must change today and you deploy weekly, the seed is the wrong home. - **Exposure.** Plaintext, permanent, readable by everyone with repo access. Personal data, contractual rates and anything under an access policy fail here immediately. ## The middle paths The interesting answers are not binary. - **Sheet-sync into a source table.** The business owner keeps editing a spreadsheet; a small scheduled job lands it in the warehouse; dbt declares it as a source with freshness and tests. Ownership stays with the business, and analytics gets a checked contract. - **A minimal internal app.** When the mapping is edited frequently and by non-technical people, a small CRUD surface backed by a real table beats both a CSV and a spreadsheet, and gives you a genuine system of record. - **Seed the default, override from a table.** Ship a seeded baseline for CI and dev reproducibility, and let a maintained table override it in production. This adds a code path and is worth it only when both reproducibility and business editing genuinely matter. ## Governance for a project with many seeds Seeds sprawl. Left ungoverned, a repo accumulates dozens of CSVs, half stale, none tested, several containing data that should never have been committed. Worth setting as policy: - Every seed has an owner named in its properties file and a description of what it is for. - Every seed has at least a uniqueness test on its key. - A size ceiling that triggers a conversation, not a hard block. - An explicit rule that personal data and secrets never enter, enforced by a secret-scanning check in CI. - A periodic sweep for seeds nothing `ref()`s any more. ## Answering this well Lead with ownership, then name the practical filters — size, change rate, sensitivity, who edits — and be explicit that the honest answer for a frequently-edited business mapping is often neither pure option but a sheet-sync or a small app. Interviewers at this level are listening for whether you reason about the change process and the people in it, not just about where bytes sit.
- What is the strongest argument against seeding a mapping that an operational system already holds?It forks the system of record. The seed has no synchronisation with the source, so it diverges the moment someone forgets to re-export, and the divergence is silent — reports quietly disagree with the operational tool. Ingesting it keeps one authority and lets you attach freshness checks and tests to the real feed.
- A finance analyst owns the fiscal calendar and cannot open a pull request. What do you do?Do not put an engineer in the middle of a routine business process. Either sync their spreadsheet into a warehouse table on a schedule and declare it as a dbt source with tests and freshness, or stand up a small editing surface over a real table. Both keep ownership with the business while giving analytics a checked contract.
- How do you keep a repository from accumulating dozens of stale seeds?Govern them like code: a named owner and description in the properties file, at least a uniqueness test on the key, a size threshold that triggers a review conversation, secret-scanning in CI, and a periodic sweep for seeds nothing references any more. Without that, half of them go stale and nobody knows which half.
saying these in an interview costs you the question
- Seeds data that an operational system already owns
- Judges the decision purely on row count
- Commits personal or contractual data because the file is small
- Treats seed versus ingest as the only two options available
- Ignores whether the data's owner can open a pull request