All skills
dbt-labs avatar

/using-dbt-for-analytics-engineering

@8908932 official
by dbt Labsdbt-labs/dbt-agent-skills729 stars
62

Builds and modifies dbt models, writes SQL transformations using ref() and source(), creates tests, and validates results with dbt show. Use when doing any dbt work - building or modifying models, debugging errors, exploring unfamiliar data sources, writing tests, or evaluating impact of changes.

Use this Skill: https://skilld.dev/gh/dbt-labs/dbt-agent-skills/using-dbt-for-analytics-engineering

This session only. Nothing lands on disk.

referencesdiscovering-data.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Discovering Data with dbt show

Use dbt show to interactively explore raw data, understand table structures, and document findings for downstream model development.

When to Use

  • Onboarding to a new dbt project with unfamiliar source data
  • Investigating data quality issues reported by stakeholders
  • Planning new models and need to understand source grain/structure
  • Mapping relationships between tables before building joins

The Iron Rule

Complete all 6 steps for every table you will build models on.

Rationalizations That Mean STOP

You're Thinking... Reality
"I don't have time for full discovery" You don't have time for wrong models.
"It's just a quick stakeholder briefing" Quick briefings become "can you build a model from this?" You need to do full discovery before building anything.
"I'll do proper discovery later" You won't. Document now or create technical debt someone else inherits.
"This is technical debt I'm accepting" You're not accepting it - you're passing it to your future self or teammates.
"47 tables is too many for full methodology" Then prioritize which tables you'll actually use and do full discovery on those. Don't half-discover everything.
"I'll just do the critical tables thoroughly" ALL tables you build on are critical. If it's not worth full discovery, don't build models on it yet.
"Standard patterns, I know this data" You know the pattern. This instance's data might vary. Verify.

Red Flags - You're About to Skip Steps

Stop if you catch yourself:

  • Running only SELECT * without grain analysis
  • Saying "the join worked" without checking orphan counts
  • Noting "some nulls" without quantifying null rates
  • Planning to "document later"
  • Feeling time pressure and reaching for shortcuts
  • Treating a large table count as permission to be less thorough

All of these mean: slow down, follow all 6 steps.

Large Scope Strategy

When facing many tables (20+), the answer is NOT abbreviated discovery. The answer is:

  1. Scope ruthlessly first - Which tables will you actually build models on? Only those need discovery now.
  2. Full methodology on scoped tables - Every table in scope gets all 6 steps. No exceptions.
  3. Explicit deferral for out-of-scope - Document which tables you're NOT discovering and why. "Not needed for current project" is valid. "Too many tables" is not.

Wrong approach: "I'll do light discovery on all 47 tables" Right approach: "I'll do full discovery on the 8 tables needed for this project"

Core Method: Iterative Discovery

Step 1: Inventory relevant objects

Sources

When discovering new raw data, list all tables from the new source. E.g. listing all ecom source tables:

# quoting is critical when selecting sources
dbt ls --select "source:ecom.*" --output json

Review the existing YAML file at original_file_path to understand what's already documented.

Models

When previewing existing models, use standard node selection syntax:

# quoting is critical when selecting multiple nodes
dbt ls --select "my_first_model my_second_model" --output json

Review existing YAML files (normally colocated with the model's original_file_path) to understand what's already documented.

Step 2: Sample Raw Data

Preview rows from each source table:

dbt show --inline "SELECT * FROM {{ source('source_name', 'table_name') }}" --limit 50 --output json

Document immediately:

  • Column names and warehouse-native data types
  • Which columns appear to be identifiers vs attributes
  • Obvious nulls, low-cardinality values, and values which are not obvious from their column name

Run standard EDA

Continue to use dbt show to run standard exploratory data analysis queries such as:

  • Identify the grain of the table
  • Check for duplicate/null primary keys
  • Validate data ranges make sense (e.g. event timestamps are in the past)
  • Profile key columns
  • Identify potential foreign key relationships
  • Inconsistent data types in a column

Documenting Findings

Create a discovery report that other agents can consume. Place in a data_discovery.md file alongside the SQL/YAML files. Do not use Jinja in these discovery files to avoid them being mistaken for doc blocks.

Discovery Report Template

## Source: {source_name}.{table_name}

### Overview
- **Row count**: X
- **Grain**: One row per [entity] per [time period]
- **Primary key**: column_name (verified unique)

### Column Analysis
| Column | Type | Nulls | Notes |
|--------|------|-------|-------|
| id | integer | 0% | Primary key |
| status | string | 2% | Values: active, inactive, pending |
| created_at | timestamp | 0% | UTC timezone |

### Data Quality Issues
- [ ] `status` has 15 rows with value "unknown" - clarify with stakeholder
- [ ] `amount` has negative values - confirm if valid or error

### Relationships
- `user_id` → `users.id` (5 orphan records found)
- `product_id` → `products.id` (clean join)

### Recommended Staging Transformations
1. Filter out `status = 'unknown'` rows or map to valid value
2. Cast `created_at` to consistent timezone
3. Add surrogate key if natural key unreliable

Previewing Data Efficiently

When using dbt show --inline to preview data, push LIMIT clauses as early as possible in CTEs to minimize data scanning. Never add a LIMIT at the end of the query - dbt show always adds an additional limit and you will cause a syntax error.

-- ✅ GOOD: Limit pushed early, minimizes scanning
with orders as (
    select * from {{ source('ecom', 'orders') }} limit 100
),
customers as (
    select * from {{ source('ecom', 'customers') }} limit 100
)
select ... from orders join customers ...

-- ❌ BAD: Full table scan before limit applied
with orders as (
    select * from {{ source('ecom', 'orders') }}
),
customers as (
    select * from {{ source('ecom', 'customers') }}
)
select ... from orders join customers ...
limit 100  -- Too late, and redundant with --limit flag

Common Mistakes

Assuming column names reflect content. Always verify with sample data; customer_id might contain account IDs

Not documenting findings. Discovery without documentation wastes effort; write it down immediately

Testing relationships on sampled data only. Orphan records may exist outside your sample; run full counts

Ignoring soft deletes. Check for deleted_at, is_active, or status columns that filter valid records

Source: SKILL.md on GitHub

1 warning17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides comprehensive guidance for dbt analytics engineering. It includes explicit defensive instructions to mitigate indirect prompt injection risks by treating warehouse data and package registry responses as untrusted content. It interacts with the official dbt Hub for package management.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: MEDIUM · 1 issue

  • Runlayer6mo

    3/9 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 8908932. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 4 months ago
What it can do
Runs commands Reads files Edits files
user-invocable
false
metadata
{
  "author": "dbt-labs"
}
All 7 allowed tools
Bash(dbt *)Bash(jq *)ReadWriteEditGlobGrep
  • Testing
  • dbt
  • analytics-engineering
  • sql
  • data-transformation
  • modeling
  • warehouse
  • elt
  • data-pipeline

README badge

README badge for dbt-labs/dbt-agent-skills/using-dbt-for-analytics-engineering

Builds and modifies dbt models, writes SQL transformations using ref() and source(), creates tests, and validates work with dbt show. Targets analytics engineering workflows including model development, refactoring, debugging, and impact assessment in existing dbt projects.

Generated from the current SKILL.md.

Does this skill work with dbt Cloud or only dbt Core?
The skill works with dbt Core via the CLI. It also integrates with dbt Cloud APIs through the dbt MCP server if available in your environment, but the primary interaction model is the dbt CLI.
Can I use this skill to query dbt's semantic layer?
No. Use the `answering-natural-language-questions-with-dbt` skill for semantic layer queries. This skill focuses on building and modifying dbt models, writing SQL transformations, and running tests.
What warehouse databases does this skill support?
The skill works with any dbt-supported warehouse (Postgres, BigQuery, Snowflake, Redshift, etc.). Some guidance is warehouse-specific (e.g., avoiding large unpartitioned scans in BigQuery), but the core dbt workflows apply universally.
Can this skill help me debug dbt errors?
Yes. The skill includes a dedicated reference guide for debugging dbt errors covering project parsing, compilation, and database errors.
Does this skill modify my dbt project directly, or just provide guidance?
The skill both provides guidance and can modify your project. It has write access to create and edit dbt models, YAML files, tests, and documentation, but follows dbt best practices like using ref() and source() and validating changes with dbt show.

Generated from the current SKILL.md. These answers refresh after source changes.