dbt Seeds & the dbt seed: A dbt Developer Hub Guide
Learn how to use dbt seeds to turn small CSV files into reliable, version-controlled tables in your warehouse. Clear use cases, configs, and examples.
On this page · 23 sections
- What is a dbt seed?
- But what makes seeds so useful?
- Typical seed use cases
- Seeds vs alternatives
- Project layout and seed configuration
- How to run seeds
- using dbt's seed with leading zeros and data checks
- End-to-end example: a tiny seed that saves a big join
- Seeds with sources, exposures, and structure
- FAQ
- What is a dbt seed?
- What are dbt seed files?
- Is dbt the same as Databricks?
- What is dbt and why is it used?
- Can I store my seeds in a directory other than the seeds directory in my project?
- Can I use seeds to load raw data?
- Do hooks run with seeds?
- How do I build one seed at a time?
- How do I preserve leading zeros in a seed?
- Practical tips
- From zero to loaded
- A note on counts, types, and governance
- Quick glossary
- Topic
- dbt for Analytics Engineers
- Category
- dbt
dbt seeds turn small CSV files into tables in your warehouse. Use a seed when you need reliable, version-controlled reference tables that change infrequently—like country codes, currency symbols, feature flags, or ID mappings. You place a CSV in your dbt project, run dbt seed, and the seed becomes a first-class table you can ref() in dbt models. This guide shows when a seed beats a join to raw data, how to configure seeds, how to preserve leading zeros, and how to build one seed at a time.
What is a dbt seed?
A dbt seed is a small, static table built from a CSV and materialized by dbt. Seeds are ideal for stable reference data you want stored directly in the data warehouse and managed in Git with your dbt project. Because a seed is static, there’s no external ingestion job or flaky upstream API—just the CSV and dbt.
In short: seeds are CSV files under version control that dbt loads into your warehouse as tables. You reference a seed with ref('seed_name') like any other model, and it participates in your lineage and downstream builds.
But what makes seeds so useful?
- Speed and reliability: A small seed avoids an extra upstream pipeline for tiny reference data.
- Governance: The seed is version controlled alongside dbt code, so reviews catch risky changes.
- Portability: Seeds run the same in dev and prod. No environment-specific scripts.
- Simplicity: No extra connectors to load csv files; dbt handles it.
Typical seed use cases
- Country codes and region mappings (ISO2/ISO3, EU membership flags).
- Currency symbols and rounding rules.
- Legacy ID to canonical ID mappings after a system migration.
- Feature flags for analytics-only toggles.
- Data quality exceptions lists (e.g., SKUs intentionally excluded from metrics).
If you’re evaluating seeds and sources together, prefer a seed when the data is static, tiny, and curated by your team; prefer a source when it originates in an operational system. For a deeper primer on references, see dbt ref() vs source(): Model-to-Table References Explained.
Seeds vs alternatives
| Option | Best for | Pros | Cons |
|---|---|---|---|
| dbt seed | Small, static reference tables | Version controlled, simple, easy to ref() |
Not meant for large datasets; full replace on run |
| Source table | Operational or raw data | Upstream ownership, scalable ingestion | Requires ingestion pipeline and monitoring |
| Hardcoded SQL/Jinja | Tiny lists embedded in a model | No files; fast to prototype | Hard to review, awkward diffs, duplicated across models |
Project layout and seed configuration
Place seeds under the seeds/ directory by default. You can nest folders to organize by domain.
my_dbt_project/
models/
seeds/
geography/
country_codes.csv
commerce/
sku_exclusions.csv
dbt_project.yml
Configure seeds in dbt_project.yml. Here’s a practical seed configuration that sets schema, quoting, and column types:
name: my_dbt_project
version: 1.0.0
profile: default
# Store seeds somewhere else? Customize the path.
seed-paths: ["seeds", "shared/reference_data"]
seeds:
+schema: reference
+quote_columns: true
geography:
country_codes:
+column_types: # preserve types and leading zeros
iso2: string
iso3: string
country_name: string
eu_member: boolean
That seed configuration ensures a consistent schema and protects formatting-sensitive fields. To preserve leading zeros in codes like "00123", specify string in column_types or quote values in the CSV.
How to run seeds
From your project root, run:
dbt seed
The run creates or replaces each seed table under the configured schema. The dbt seed command loads all eligible files; to build one seed at a time, select it explicitly:
# By name
dbt seed --select country_codes
# By path
dbt seed --select path:seeds/geography/country_codes.csv
Because a seed is static, dbt fully reloads it each time. If you need incremental behavior, a model is a better fit.
using dbt's seed with leading zeros and data checks
For CSVs with padded numeric strings, set +column_types to string and write a quick test to catch accidental numeric casts:
# tests/assert_iso2_format.sql
select *
from {{ ref('country_codes') }}
where length(iso2) != 2 or iso2 != upper(iso2)
Attach that to the seed in YAML:
version: 2
seeds:
- name: country_codes
description: ISO mappings for countries
tests:
- not_null:
column_name: iso2
- unique:
column_name: iso2
- assert_iso2_format
End-to-end example: a tiny seed that saves a big join
Your orders table has 40M rows. You need a reliable region field per order. Instead of joining to a raw data API snapshot with inconsistent keys, create a small country_codes seed and join locally.
-- models/fct_orders.sql
with base as (
select * from {{ ref('stg_orders') }} -- staged from raw data
),
geo as (
select * from {{ ref('country_codes') }} -- the seed
)
select
b.order_id,
b.country_iso2,
g.region,
b.order_total
from base b
left join geo g
on b.country_iso2 = g.iso2;
That seed makes the transformation deterministic, avoids flakey upstream merges, and keeps the dataset logic close to your dbt models. Because the seed is version controlled, reviewers can audit changes that affect downstream models.
Seeds with sources, exposures, and structure
For a mental model of seeds and sources: seeds are curated reference data you author; sources are external tables you declare. Use the ref/source patterns consistently; see dbt ref() vs source(): Model-to-Table References Explained.
If you publish key semantic assets built atop a seed, document them with exposures; the dbt Exposures: Exposure Lineage, Selectors — dbt Developer Hub guide shows how to capture downstream dashboards and notebooks.
For recommended folders and naming across your dbt project, skim dbt Project Structure: Staging, Intermediate, and Marts Done Right. If you need a full calendar, prefer a generated model over a seed; see dbt Date Spine: Build a Calendar Hub Table.
FAQ
What is a dbt seed?
A seed is a CSV turned into a table by dbt. It’s static, small, and ideal for reference data your team curates.
What are dbt seed files?
A seed file is a CSV file placed under your project’s seed paths that dbt loads into your data warehouse as a table when you run dbt seed.
Is dbt the same as Databricks?
No. dbt is a framework for SQL-first data transformation and modeling; Databricks is a lakehouse platform. Many teams use dbt on Databricks, but they are different tools. For understanding dbt, start at the dbt topic hub.
What is dbt and why is it used?
dbt lets analytics engineers use dbt to manage SQL models, tests, documentation, and deployments as code. It standardizes data transformation in the warehouse and integrates with your data pipeline for reliable, reviewable builds.
Can I store my seeds in a directory other than the seeds directory in my project?
Yes. Set seed-paths in dbt_project.yml to any list of folders. You can also nest subdirectories for domain separation.
Can I use seeds to load raw data?
Generally no. Seeds are for small, static reference data. For large or fast-changing raw data, declare a source and ingest via your warehouse or EL tools. Then join the source to a seed when you only need a tiny curated mapping.
Do hooks run with seeds?
Model pre-hook/post-hook configs don’t run for seeds. Project-level on-run-start/on-run-end do run for a seed invocation, so you can log or set session vars if needed.
How do I build one seed at a time?
Use selection syntax: dbt seed --select country_codes or dbt seed --select path:seeds/geography/country_codes.csv.
How do I preserve leading zeros in a seed?
Set the seed’s +column_types to string (or your warehouse’s text type) for those columns, or quote the values in the CSV. Tests can enforce formatting.
Practical tips
- Size: Keep each seed small. If a seed grows into thousands of lines that change weekly, move it to an external table.
- Review process: Because a seed is version-controlled, treat it like code. Reviews should verify semantic changes, not just diffs.
- Quoting: Quote values in the CSV when whitespace or leading zeros matter, and match with explicit types.
- Naming: Use clear, singular names for each seed. Name columns to match join keys used in downstream models.
- Schema: Put seeds in a dedicated schema (e.g.,
reference) so they’re easy to find and govern.
From zero to loaded
To load the seed and make it available for downstream work, put a CSV under your seed path, configure types, and run dbt seed to load into your data warehouse. After that, the data in your data warehouse includes a small, curated table that’s easy to join to and reason about. This is the simplest way to manage static data in your data without an external job, and it fits cleanly into any data pipeline.
A note on counts, types, and governance
Because seeds are static, treat them as documentation-backed contracts. Define column types, add tests, and audit changes. If your seed data starts to drift from reference data into general-purpose facts, migrate it to a proper ingested table to keep your pipeline sustainable.
Quick glossary
- Seed: A CSV-backed, static table built by dbt.
- Seed data: Curated mappings or lists committed with code.
- Seed file: The on-disk CSV for a seed.
- dbt seed: The CLI action that builds seeds.
- Dataset: Any collection of related records; seeds are tiny datasets.
If you’re ready to use dbt seeds in a real project, remember: seeds are csv files, scoped and deliberate. They shine when they’re small, stable, and clearly owned. For more on lineage and publishing analytics built on seeds, revisit the exposures guide on the dbt developer hub.
Keep learning: explore the dbt topic hub, and practice with our free graded exercises at /practice.
- dbt
dbt Seeds & the dbt seed: A dbt Developer Hub Guide
Learn how to use dbt seeds to turn small CSV files into reliable, version-controlled tables in your warehouse. Clear use cases, configs, and examples.
- dbt
dbt Date Spine: Build a Calendar Hub Table
Build a reliable dbt date spine and calendar hub table fast. Use dbt_utils, variables for start/end dates, and proven patterns that scale.
- dbt
dbt Exposures: Exposure Lineage, Selectors — dbt Developer Hub
dbt exposures connect dashboards, notebooks, and apps to the dbt DAG. Learn how to define, automate, and use them for safe changes and clear lineage.
